Using C++ edition components in plain C

Introduction

The C++ editions can be used from plain C. The library itself exports plain C interfaces. In the header files located in the "include" folder of your installation directory you will find the function definitions (as well as other information like events) that you will need to call from your C program. For instance, in the sftp.h file included in IPWorks SSH:

IPWORKSSSH_EXTERNAL void* IPWORKSSSH_CALL IPWorksSSH_SFTP_Create(PIPWORKSSSH_CALLBACK lpSink, void *lpContext, char *lpOemKey, int opts);
IPWORKSSSH_EXTERNAL int   IPWORKSSSH_CALL IPWorksSSH_SFTP_Destroy(void *lpObj);
IPWORKSSSH_EXTERNAL int   IPWORKSSSH_CALL IPWorksSSH_SFTP_CheckIndex(void *lpObj, int propid, int arridx);
IPWORKSSSH_EXTERNAL void* IPWORKSSSH_CALL IPWorksSSH_SFTP_Get(void *lpObj, int propid, int arridx, int *lpcbVal, int64 *lpllVal);
IPWORKSSSH_EXTERNAL int   IPWORKSSSH_CALL IPWorksSSH_SFTP_Set(void *lpObj, int propid, int arridx, const void *val, int cbVal);
IPWORKSSSH_EXTERNAL int   IPWORKSSSH_CALL IPWorksSSH_SFTP_Do(void *lpObj, int methid, int cparam, void *param[], int cbparam[], int64 *lpllVal);
IPWORKSSSH_EXTERNAL char* IPWORKSSSH_CALL IPWorksSSH_SFTP_GetLastError(void *lpObj);
IPWORKSSSH_EXTERNAL int   IPWORKSSSH_CALL IPWorksSSH_SFTP_GetLastErrorCode(void *lpObj);
IPWORKSSSH_EXTERNAL int   IPWORKSSSH_CALL IPWorksSSH_SFTP_SetLastErrorAndCode(void *lpObj, int code, char *message);
IPWORKSSSH_EXTERNAL char* IPWORKSSSH_CALL IPWorksSSH_SFTP_GetEventError(void *lpObj);
IPWORKSSSH_EXTERNAL int   IPWORKSSSH_CALL IPWorksSSH_SFTP_GetEventErrorCode(void *lpObj);
IPWORKSSSH_EXTERNAL int   IPWORKSSSH_CALL IPWorksSSH_SFTP_SetEventErrorAndCode(void *lpObj, int code, char *message);
IPWORKSSSH_EXTERNAL int   IPWORKSSSH_CALL IPWorksSSH_SFTP_StaticInit(void *hInst);
IPWORKSSSH_EXTERNAL int   IPWORKSSSH_CALL IPWorksSSH_SFTP_StaticDestroy();

Defining Methods, Properties, Events, and Types

A component's events, properties, methods, and any types will also have to be explicitly defined as constants within the context of your program.

// Event constants
#define EVENT_CONNECTED (1)
...
#define EVENT_TRANSFER (13)

//Property Constants
#define PROP_DIRLISTCOUNT (2)
...
#define PROP_SSHUSER (50)

//Method Constants
#define METHOD_DOEVENTS (7)
...
#define METHOD_SSHLOGON (24)

//Other Constants
#define SSHAUTHMODE_PASSWORD (2)
/*** END DEFINE ***/

Each property, method and event has its own index, which can be determined by examining the relevant header file. In the case that a property call requires an array index (arridx parameter) or data length (*lpcbVal parameter), these parameters can be set as necessary. For example, the SetConnected method in the sftp.h file provides the propid for the connected property (1):

inline int SetConnected(int bConnected) {
      void* val = (void*)IPH64CAST(bConnected);
      return IPWorksSSH_SFTP_Set(m_pObj, 1, 0, val, 0);
    }

For some items, like event parameters, type definitions will also need to be provided. For example, the Connected event parameters are defined like so:

typedef struct {
  int StatusCode;
  const char *Description;
  int reserved;
} SFTPConnectedEventParams;

Since the C program will not be using the header files, the function definitions from the header file will need to be defined. For example, the SFTP function definitions would be added like this:

void* IPWORKSSSH_CALL IPWorksSSH_EvtStr(void* lpEvtStr, int id, void* val, int opt); //from ipworksssh.h
void* IPWORKSSSH_CALL IPWorksSSH_SFTP_Create(PIPWORKSSSH_CALLBACK lpSink, void* lpContext, char* lpOemKey, int opts);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_Destroy(void* lpObj);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_CheckIndex(void* lpObj, int propid, int arridx);
void* IPWORKSSSH_CALL IPWorksSSH_SFTP_Get(void* lpObj, int propid, int arridx, int* lpcbVal, int64* lpllVal);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_Set(void* lpObj, int propid, int arridx, const void* val, int cbVal);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_Do(void* lpObj, int methid, int cparam, void* param[], int cbparam[], int64* lpllVal);
char* IPWORKSSSH_CALL IPWorksSSH_SFTP_GetLastError(void* lpObj);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_GetLastErrorCode(void* lpObj);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_StaticInit(void* hInst);

Implementing Events

When the SFTP_Create method is called, the "SFTP_CALLBACK lpSink" parameter defines the callback function used to fire events through. The SFTPEventSink method within the header file contains the available event types, IDs, and parameters and can be added to the program to handle events. Using the switch statement in the SFTPEventSink can avoid creating/implementing the Fire*** methods. For example:

static int IPWORKSSSH_CALL SFTPEventSink(void* lpObj, int event_id, int cparam, void* param[], int cbparam[]) {
	int ret_code = 0;

	switch (event_id) {
	case EVENT_CONNECTED: {
		SFTPConnectedEventParams e = { (int)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), 0 };
		break;
	}
	case EVENT_CONNECTIONSTATUS: {
		SFTPConnectionStatusEventParams e = { (char*)IPH64CAST(param[0]), (int)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), 0 };
		break;
	}
	...
}
return ret_code;
}

Calling Methods and Setting Properties

Once everything is defined, the functions can be called. For example, to set the SSHUser property on an SFTP component:

SFTP_Set(m_pObj, PROP_SSHUSER, 0, (void*)"USER", 0);

Note: More examples on how to call use each property and method can be found in the header file.

Compilation

The program can be compiled on a Unix/Linux system or on Windows just like any other C program. For Unix/Linux a good choice is gcc/g++. On Windows, Visual Studio includes a C compiler by the name of cl.exe which can be find in YourVSDirectory/VC/bin. Make sure to compile with a reference to the library that is being used. An example of compiling the SFTP program can be found here:

cl.exe /Tc .\sftp_demo.c .\ipworksssh20s.lib

Full Example

A full example might look something like this:

#include <stdio.h>

/*** DEFINE ***/
#define IPWORKSSSH_CALL __stdcall // Comes from ipworksssh.h
#define IPH64CAST (ns_int64) // Comes from ipworksssh.h

// Event constants
#define EVENT_CONNECTED (1)
#define EVENT_CONNECTIONSTATUS (2)
#define EVENT_DIRLIST (3)
#define EVENT_DISCONNECTED (4)
#define EVENT_ENDTRANSFER (5)
#define EVENT_ERROR (6)
#define EVENT_SSHKEYBOARDINTERACTIVE (9)
#define EVENT_SSHSERVERAUTHENTICATION (10)
#define EVENT_SSHSTATUS (11)
#define EVENT_STARTTRANSFER (12)
#define EVENT_TRANSFER (13)

//Property Constants
#define PROP_DIRLISTCOUNT (2)
#define PROP_DIRLISTENTRY (3)
#define PROP_DIRLISTFILENAME (4)
#define PROP_DIRLISTFILESIZE (5)
#define PROP_DIRLISTFILETIME (6)
#define PROP_DIRLISTISDIR (7)
#define PROP_DIRLISTISSYMLINK (8)
#define PROP_FILEACCESSTIME (9)
#define PROP_LOCALFILE (32)
#define PROP_REMOTEFILE (36)
#define PROP_REMOTEPATH (37)
#define PROP_SSHAUTHMODE (39)
#define PROP_SSHHOST (47)
#define PROP_SSHPASSWORD (48)
#define PROP_SSHPORT (49)
#define PROP_SSHUSER (50)

//Method Constants
#define METHOD_DOEVENTS (7)
#define METHOD_LISTDIRECTORY (13)
#define METHOD_SSHLOGOFF (23)
#define METHOD_SSHLOGON (24)

#define SSHAUTHMODE_PASSWORD (2)
/*** END DEFINE ***/

/**** TYPEDEFS ****/
typedef long int ns_int64; // Comes from ipworksssh.h
typedef unsigned long int ns_uint64; // Comes from ipworksssh.h
typedef __int64 int64;

typedef struct {
	int StatusCode;
	const char* Description;
	int reserved;
} SFTPConnectedEventParams;

typedef struct {
	const char* ConnectionEvent;
	int StatusCode;
	const char* Description;
	int reserved;
} SFTPConnectionStatusEventParams;

typedef struct {
	const char* DirEntry;
	const char* FileName;
	int IsDir;
	int64 FileSize;
	const char* FileTime;
	int IsSymlink;
	int reserved;
} SFTPDirListEventParams;

typedef struct {
	int StatusCode;
	const char* Description;
	int reserved;
} SFTPDisconnectedEventParams;

typedef struct {
	int Direction;
	const char* LocalFile;
	const char* RemoteFile;
	int reserved;
} SFTPEndTransferEventParams;

typedef struct {
	int ErrorCode;
	const char* Description;
	const char* LocalFile;
	const char* RemoteFile;
	int reserved;
} SFTPErrorEventParams;

typedef struct {
	int LogLevel;
	const char* Message;
	const char* LogType;
	int reserved;
} SFTPLogEventParams;

typedef struct {
	char* Packet;
	int reserved;
} SFTPSSHCustomAuthEventParams;

typedef struct {
	const char* Name;
	const char* Instructions;
	const char* Prompt;
	char* Response;
	int EchoResponse;
	int reserved;
} SFTPSSHKeyboardInteractiveEventParams;

typedef struct {
	const char* HostKey;
	int lenHostKey;
	const char* Fingerprint;
	const char* KeyAlgorithm;
	const char* CertSubject;
	const char* CertIssuer;
	const char* Status;
	int Accept;
	int reserved;
} SFTPSSHServerAuthenticationEventParams;

typedef struct {
	const char* Message;
	int reserved;
} SFTPSSHStatusEventParams;

typedef struct {
	int Direction;
	const char* LocalFile;
	const char* RemoteFile;
	int reserved;
} SFTPStartTransferEventParams;

typedef struct {
	int Direction;
	const char* LocalFile;
	const char* RemoteFile;
	int64 BytesTransferred;
	int PercentDone;
	const char* Text;
	int lenText;
	int Cancel;
	int reserved;
} SFTPTransferEventParams;
/**** END TYPEDEFS ****/

typedef int (IPWORKSSSH_CALL* PIPWORKSSSH_CALLBACK) (void* lpObj, int event_id, int cparam, void* param[], int cbparam[]);

/*** FUNCTION DEFINITIONS ***/
void* IPWORKSSSH_CALL IPWorksSSH_EvtStr(void* lpEvtStr, int id, void* val, int opt); //from ipworksssh.h
void* IPWORKSSSH_CALL IPWorksSSH_SFTP_Create(PIPWORKSSSH_CALLBACK lpSink, void* lpContext, char* lpOemKey, int opts);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_Destroy(void* lpObj);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_CheckIndex(void* lpObj, int propid, int arridx);
void* IPWORKSSSH_CALL IPWorksSSH_SFTP_Get(void* lpObj, int propid, int arridx, int* lpcbVal, int64* lpllVal);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_Set(void* lpObj, int propid, int arridx, const void* val, int cbVal);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_Do(void* lpObj, int methid, int cparam, void* param[], int cbparam[], int64* lpllVal);
char* IPWORKSSSH_CALL IPWorksSSH_SFTP_GetLastError(void* lpObj);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_GetLastErrorCode(void* lpObj);
int   IPWORKSSSH_CALL IPWorksSSH_SFTP_StaticInit(void* hInst);

static int IPWORKSSSH_CALL SFTPEventSink(void* lpObj, int event_id, int cparam, void* param[], int cbparam[]) {
	int ret_code = 0;

	switch (event_id) {
	case EVENT_CONNECTED: {
		SFTPConnectedEventParams e = { (int)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), 0 };
		break;
	}
	case EVENT_CONNECTIONSTATUS: {
		SFTPConnectionStatusEventParams e = { (char*)IPH64CAST(param[0]), (int)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), 0 };
		break;
	}
	case EVENT_DIRLIST: {
		SFTPDirListEventParams e = { (char*)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), (int)IPH64CAST(param[2]), *(int64*)IPH64CAST(param[3]), (char*)IPH64CAST(param[4]), (int)IPH64CAST(param[5]), 0 };
		
		//Can optionally list through event
		//printf("File: %s\n",e.DirEntry);
		break;
	}
	case EVENT_DISCONNECTED: {
		SFTPDisconnectedEventParams e = { (int)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), 0 };
		break;
	}
	case EVENT_ENDTRANSFER: {
		SFTPEndTransferEventParams e = { (int)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), 0 };
		break;
	}
	case EVENT_ERROR: {
		SFTPErrorEventParams e = { (int)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), (char*)IPH64CAST(param[3]), 0 };
		break;
	}
	case EVENT_SSHKEYBOARDINTERACTIVE: {
		SFTPSSHKeyboardInteractiveEventParams e = { (char*)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), (char*)IPWorksSSH_EvtStr(param[3], 0, NULL, 1), (int)IPH64CAST(param[4]), 0 };
		param[3] = (void*)(e.Response);
		break;
	}
	case EVENT_SSHSERVERAUTHENTICATION: {
		SFTPSSHServerAuthenticationEventParams e = { (char*)IPH64CAST(param[0]), (int)IPH64CAST(cbparam[0]), (char*)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), (char*)IPH64CAST(param[3]), (char*)IPH64CAST(param[4]), (char*)IPH64CAST(param[5]), (int)IPH64CAST(param[6]), 0 };

		e.Accept = 1; // true

		param[6] = (void*)(e.Accept);
		break;
	}
	case EVENT_SSHSTATUS: {
		SFTPSSHStatusEventParams e = { (char*)IPH64CAST(param[0]),  0 };
		printf(e.Message);
		getchar();
		break;
	}
	case EVENT_STARTTRANSFER: {
		SFTPStartTransferEventParams e = { (int)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), 0 };
		break;
	}
	case EVENT_TRANSFER: {
		SFTPTransferEventParams e = { (int)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), *(int64*)IPH64CAST(param[3]), (int)IPH64CAST(param[4]), (char*)IPH64CAST(param[5]), (int)IPH64CAST(cbparam[5]), (int)IPH64CAST(param[6]), 0 };
		break;
	}

	}
	return ret_code;
}



void* m_pObj;

int main()
{
	int ret_code = 0;
	int index;
	
	printf("Press Enter to continue: ");
	getchar();
	
	IPWorksSSH_SFTP_StaticInit(NULL);
	m_pObj = IPWorksSSH_SFTP_Create(SFTPEventSink, (void*)m_pObj, (char*)"my_string", 0);

	IPWorksSSH_SFTP_Set(m_pObj, PROP_SSHHOST, 0, (void*)"HOSTNAME", 0);
	IPWorksSSH_SFTP_Set(m_pObj, PROP_SSHPORT, 0, (void*)22, 0);
	IPWorksSSH_SFTP_Set(m_pObj, PROP_SSHAUTHMODE, 0, (void*)SSHAUTHMODE_PASSWORD, 0);
	IPWorksSSH_SFTP_Set(m_pObj, PROP_SSHUSER, 0, (void*)"USERNAME", 0);
	IPWorksSSH_SFTP_Set(m_pObj, PROP_SSHPASSWORD, 0, (void*)"PASSWORD", 0);

	ret_code = IPWorksSSH_SFTP_Do(m_pObj, METHOD_LISTDIRECTORY, 0, 0, 0, 0);

	for (index = 0; index < (int)(long)IPWorksSSH_SFTP_Get(m_pObj, PROP_DIRLISTCOUNT, 0, 0, 0); index++) {
		printf("Item: %s\n", (char*)IPWorksSSH_SFTP_Get(m_pObj, PROP_DIRLISTENTRY, index, 0, 0));
	}

	if (ret_code) {
		printf(IPWorksSSH_SFTP_GetLastError(m_pObj));
	}

	getchar();
	IPWorksSSH_SFTP_Destroy(m_pObj);
	return 0;
}

We appreciate your feedback.  If you have any questions, comments, or suggestions about this article please contact our support team at kb@nsoftware.com.