#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
#include <errno.h>

#define ERRBUFSIZE	1024 

char store[] = "./";
char certificatepath[] = "./cert2.pem";
char passphraseval[] = "password";
char pageurl[] = "https://NN.XXX.com/Upload.asp?Id=[345]";

struct xml_rec
{
	unsigned long batchno;
	char errbuf[ERRBUFSIZE];
	char filename[64];
};


int saveXML(struct xml_rec *xmlrec)
{
	FILE *fp;
	time_t timenow = time(NULL);
	struct tm *timestruct;
	char *filepath;
	char filenameandpath[256];
	char datestring[11];

	// first get the file path for saved files
	filepath = store;

	if (filepath == NULL)
	{
		return (-1);
	}

	// now format the filename for this xml. Format is batch_no-YYYYMMDDSS
	// first get the time
	timestruct = localtime(&timenow);
	strftime(datestring, sizeof(datestring), "%Y%m%d%S", timestruct);

	// now put the filename into the structure
	snprintf(xmlrec->filename, 64, "%lu-%s.xml", xmlrec->batchno, datestring);
	snprintf(filenameandpath, sizeof(filenameandpath), "%s/%s", filepath, xmlrec->filename);

	// now open a file for writing
	fp = fopen(filenameandpath, "w");
	if (!fp)
	{
		printf("Could not write XML file [%s]. %s. Aborting\n", strerror(errno), filenameandpath);
		return (-1);
	}

	// opened the file for writing, now put the xml text into it
	fprintf(fp, "%s\n", xmlstring);
	fclose(fp);

	return (0);
}

/*
 * writeResponse
 *
 * This is the libcurl function handler for text replies to the POSTing of data. Data
 * is sent to this function and written to the specified file
 *
 * The size of data pointed to by ptr is (size X nmemb). N.B. It will NOT be Null terminated
 *
 */
size_t writeResponse(void *ptr, size_t size, size_t nmemb, void *stream)
{
	int written = 0;
	written = fwrite(ptr, size, nmemb, (FILE *)stream);
	return (written);
}


int sendToSite(struct xml_rec *xmlrec)
{
	CURL *curl;
	const char *keyType = "PEM";
	FILE *responsefile;
	FILE *headerfile;
	char *certificate;
	char *passphrase;
	char *url;
	char filenameandpath[256] = "\0";
	char rspfilenameandpath[256] = "\0";
	char hdrfilenameandpath[256] = "\0";
	char curlerrbuf[CURL_ERROR_SIZE];
	struct HttpPost *formpost=NULL;
	struct HttpPost *lastptr=NULL;
	CURLcode res;

	// get the path of the certificate
	certificate = certificatepath;
	if (certificate == NULL)
	{
		printf("No cretificate\n");
		return (-1);
	}
	
	// get the passphrase
	passphrase = passphraseval;
	if (passphrase == NULL)
	{
		printf("No passphrase\n");
		return (-1);
	}

	// get the upload url
	url = pageurl;
	if (url == NULL)
	{
		printf("No URL\n");
		return (-1);
	}

	// before doing the curl stuff, we save a copy of the XML in a file
	if (saveXML(xmlrec) != 0)
	{
		return (-1);
	}
	
	// now generate the filename
	snprintf(filenameandpath, sizeof(filenameandpath), "%s/%s", 
			store,
			xmlrec->filename
			);

	// now set the response file name, same filename as before with .rsp tagged on
	snprintf(rspfilenameandpath, sizeof(rspfilenameandpath), "%s.rsp", filenameandpath);

	// now open the response file for writing
	responsefile = fopen(rspfilenameandpath, "w");
	if (responsefile == NULL)
	{
		printf("Could not write XML response file [%s]. %s. Aborting", strerror(errno), rspfilenameandpath);
		return (-1);
	}

	// now set the response file name, same filename as before with .rsp tagged on
	snprintf(hdrfilenameandpath, sizeof(rspfilenameandpath), "%s.hdr", filenameandpath);
	// now open a header file
	headerfile = fopen(hdrfilenameandpath, "w");
	if (responsefile == NULL)
	{
		printf("Could not write XML header file [%s]. %s. Aborting", strerror(errno), hdrfilenameandpath);
		return (-1);
	}

	

	// now start to setup curl
	res = curl_global_init(CURL_GLOBAL_DEFAULT);
	if (res != CURLE_OK)
	{
		printf("Could not curl_global_init(%d) [%s]", res, curlerrbuf);
		return (-1);
	}

	/* fill in the form data */
	res = curl_formadd(&formpost,
			&lastptr,
			CURLFORM_COPYNAME, "File1",
			CURLFORM_COPYCONTENTS, filenameandpath,
			CURLFORM_END);
	if (res != CURLE_OK)
	{
		printf("Could not formadd File1(%d) [%s]", res, curlerrbuf);
		return (-1);
	}

	/* fill in the submit field too, even if this is rarely needed */
	res = curl_formadd(&formpost,
			&lastptr,
			CURLFORM_COPYNAME, "Action",
			CURLFORM_COPYCONTENTS, "Upload the File",
			CURLFORM_END);
	if (res != CURLE_OK)
	{
		printf("Could not formadd Action(%d) [%s]", res, curlerrbuf);
		return (-1);
	}

	curl = curl_easy_init();
	if (curl)
	{
		res = curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);

		// register with curl an errorbuffer
		res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curlerrbuf);
		if (res != CURLE_OK)
		{
			printf("Could not set ERRORBUFFER(%d) [%s]", res, curlerrbuf);
			curl_easy_cleanup(curl);
			curl_formfree(formpost);
			curl_global_cleanup();
			return (-1);
		}

		// dont want a progress meter
		res = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
		if (res != CURLE_OK)
		{
			printf("Could not set NOPROGRESS(%d) [%s]", res, curlerrbuf);
			curl_easy_cleanup(curl);
			curl_formfree(formpost);
			curl_global_cleanup();
			return (-1);
		}

		// send all the data we receive to this function
		res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeResponse);
		if (res != CURLE_OK)
		{
			printf("Could not set WRITEFUNCTION(%d) [%s]", res, curlerrbuf);
			curl_easy_cleanup(curl);
			curl_formfree(formpost);
			curl_global_cleanup();
			return (-1);
		}

		// certificate is PEM format
		res = curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, keyType);
		if (res != CURLE_OK)
		{
			printf("Could not set SSLCERTTYPE(%d) [%s]", res, curlerrbuf);
			curl_easy_cleanup(curl);
			curl_formfree(formpost);
			curl_global_cleanup();
			return (-1);
		}
		// set the certificate file
		res = curl_easy_setopt(curl, CURLOPT_SSLCERT, certificate);
		if (res != CURLE_OK)
		{
			printf("Could not set SSLCERT(%d) [%s]", res, curlerrbuf);
			curl_easy_cleanup(curl);
			curl_formfree(formpost);
			curl_global_cleanup();
			return (-1);
		}
		// and the certificate has a passphrase
		res = curl_easy_setopt(curl, CURLOPT_SSLCERTPASSWD, passphrase);
		if (res != CURLE_OK)
		{
			printf("Could not set SSLCERTPASSWD(%d) [%s]", res, curlerrbuf);
			curl_easy_cleanup(curl);
			curl_formfree(formpost);
			curl_global_cleanup();
			return (-1);
		}
		
		// set the url we are posting to
		res = curl_easy_setopt(curl, CURLOPT_URL, url);
		if (res != CURLE_OK)
		{
			printf("Could not set URL(%d) [%s]", res, curlerrbuf);
			curl_easy_cleanup(curl);
			curl_formfree(formpost);
			curl_global_cleanup();
			return (-1);
		}

		// set the file that we want to write the return data to
		res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, responsefile);
		if (res != CURLE_OK)
		{
			printf("Could not set WRITEDATA(%d) [%s]", res, curlerrbuf);
			curl_easy_cleanup(curl);
			curl_formfree(formpost);
			curl_global_cleanup();
			return (-1);
		}

		// set the file for the header
		res = curl_easy_setopt(curl, CURLOPT_WRITEHEADER, headerfile);
		if (res != CURLE_OK)
		{
			printf("Could not set WRITEHEADER(%d) [%s]", res, curlerrbuf);
			curl_easy_cleanup(curl);
			curl_formfree(formpost);
			curl_global_cleanup();
			return (-1);
		}

		// set that we want a multipart/formdata POST using our formpost linked list
		res = curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
		if (res != CURLE_OK)
		{
			printf("Could not set HTTPPOST(%d) [%s]", res, curlerrbuf);
			curl_easy_cleanup(curl);
			curl_formfree(formpost);
			curl_global_cleanup();
			return (-1);
		}

		// do the post!
		res = curl_easy_perform(curl);
		if (res != CURLE_OK)
		{
			printf("Could not do curl_easy_perform(%d) [%s]", res, curlerrbuf);
			curl_easy_cleanup(curl);
			curl_formfree(formpost);
			curl_global_cleanup();
			return (-1);
		}

		// cleanup
		curl_easy_cleanup(curl);
		// empty the formpost linked list
		curl_formfree(formpost);
	}
	else
	{
		// could not get a curl handle
		printf("Could not get curl handle [%s]", curlerrbuf);
		return (-1);
	}

	curl_global_cleanup();

	return (0);
}

int main()
{
	struct xml_rec xmlrec;
	int ret;

	xmlrec.batchno = 3456;
	sprintf(xmlstring, "THIS IS JUST\n A TEST");

	ret = sendToSite(&xmlrec);

	if (ret == 0)
	{
		printf("OK\n");
	}
	else
	{
		printf("\n%s\n", xmlrec.errbuf);
	}

	return 0;
}


