/*	dimesrv.cpp

	Example simple image server using DIME,
	Adapted by Ch. Aberger to demonstrate dime for Win32 IIS. 
	Copyright (C) 2000-2002 Robert A. van Engelen. All Rights Reserved.
	Copyright (C) 2003 Christian T. Aberger.

	Runs as mod_gsoap (http://www.aberger.at/SOAP) as IIS SOAP service
	Web service

	NOTE: THE SERVER WILL ONLY SEND FILES THAT ARE IN THE CURRENT DIR FOR
	SECURITY REASONS. HOWEVER, THE AUTHOR IS NOT RESPONSIBLE FOR ANY DAMAGES
	THAT MAY RESULT FROM THE USE OF THIS PROGRAM.
	AND ALSO ABERGER IS RESPONSIBLE FOR NOTHING.
*/

#include "soapH.h"
#include "dime.nsmap"
#include <sys/stat.h>	// use fstat() for streaming DIME
#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
#include <windows.h>

#define MAX_FILE_SIZE (10000)	// Max. file size

// streaming DIME callbacks for sending data to client.
static void *dime_read_open(struct soap*, void*, const char*, const char*, const char*);
static void dime_read_close(struct soap*, void*);
static size_t dime_read(struct soap*, void*, char*, size_t);

// streaming DIME callbacks for receiving data from client.
static void *dime_write_open(struct soap*, const char*, const char*, const char*);
static void dime_write_close(struct soap*, void*);
static int dime_write(struct soap*, void*, const char*, size_t);


extern "C" {

/** This function is called by mod_gsoap after the dll was successfully loaded and before processing begins.
	You can do any one-time initialization here.
*/
int mod_gsoap_init() {
	// todo: add your initialization code here 
	return SOAP_OK;
}
/** This function is called after all processing was done before dll is unloaded.
	You can do any cleanup here.
*/
int mod_gsoap_terminate() {
	// todo: add your termination code here 
	return SOAP_OK;
}

}


int ns__getImage(struct soap *soap, char *name, xsd__base64Binary &image) { 
	/* in this sample, due to security reasons the file must be in the system's %TEMP% folder */
	TCHAR szPath[_MAX_PATH];
	if (0 == ::GetTempPath(sizeof szPath, szPath)) {
		return soap_receiver_fault(soap, "cannot find the TEMP folder", NULL);
	}
	if (name) { 
		FILE *fd = NULL;
		// do some checks on the file name to verify it is local:
		if (!strchr(name, '/') && !strchr(name, '\\') && !strchr(name, ':')) {
			strcat(szPath, name);
			fd = fopen(szPath, "rb");
		}
		if (!fd) {
			char szMsg[MAX_PATH + 64];
			strcpy(szMsg, "Cannot open file: ");
			strcat(szMsg, szPath);
			return soap_receiver_fault(soap, szMsg, NULL);
		}
		struct stat sb;
		if (!fstat(fileno(fd), &sb) && sb.st_size > 0) { // since we can get the length of the file, we can stream it
		  soap->fdimereadopen = dime_read_open;
		  soap->fdimereadclose = dime_read_close;
		  soap->fdimeread = dime_read;
		  image.__ptr = (unsigned char*)fd; // must set to non-NULL (this is our fd handle which we need in the callbacks)
		  image.__size = sb.st_size; // must set size
		} else { // don't know the size, so buffer it
			image.__ptr = (unsigned char*)soap_malloc(soap, MAX_FILE_SIZE);
			for (int i = 0; i < MAX_FILE_SIZE; i++) {
				int c;
				if ((c = fgetc(fd)) == EOF) {
					break;
				}
				image.__ptr[i] = c;
			}
			fclose(fd);
			image.__size = i;
		}
	    image.type = "image/jpeg";
		image.options = soap_dime_option(soap, 0, "My picture");
	} else {
		return soap_receiver_fault(soap, "Name required", NULL);
	}
	return SOAP_OK;
}

/** save a file sent by the client to our server */
static void *dime_read_open(struct soap *soap, void *handle, const char *id, const char *type, const char *options)
{ // we should return NULL without setting soap->error if we don't want to use the streaming callback for this DIME attachment. The handle contains the non-NULL __ptr field value which should have been set in the application.
  // the value of the handle can be changed and will be passed on to the fdimeread and fdimereadclose callbacks. The value will not affect the __ptr field.
  return handle;
}

static void dime_read_close(struct soap *soap, void *handle)
{ fclose((FILE*)handle);
}

static size_t dime_read(struct soap *soap, void *handle, char *buf, size_t len)
{ return fread(buf, 1, len, (FILE*)handle);
}

int ns__putImage(struct soap *soap, char *name, xsd__base64Binary *image, int &status) { 
	int nRet = SOAP_OK;
	TCHAR szPath[_MAX_PATH];
	if (0 == ::GetTempPath(sizeof szPath, szPath)) {
		return soap_receiver_fault(soap, "cannot find the TEMP folder", NULL);
	}
	strcat(szPath, "upload");
	if (INVALID_FILE_ATTRIBUTES == ::GetFileAttributes(szPath)) {
		::CreateDirectory(szPath, NULL); // create it if it ain't exist.
		if (INVALID_FILE_ATTRIBUTES == ::GetFileAttributes(szPath)) {
			return soap_receiver_fault(soap, "Failed to create output directory", szPath);
		}
	}
	strcat(szPath, "\\");
	strcat(szPath, name);
	FILE *fp = fopen(szPath, "wb");
	status = 0;
	if (NULL != fp) {
		status = fwrite(image->__ptr, sizeof(char), image->__size, fp);
		fclose(fp);
	} else {
		return soap_receiver_fault(soap, "Failed to open output file", szPath);
	}
	if (status != image->__size) {
		return soap_receiver_fault(soap, "Failed to write all bytes to file.", szPath);
	}
	return SOAP_OK;
}
