/*
	get.dll - DLL for simple http requests via libcurl
		- Is threadsafe, supports only one get at a time though
	Jason A. Petrasko, 2007, Public Domain
*/

#ifndef GET_HEADER_FILE
#define GET_HEADER_FILE

// this means that get will never download more than 64MB into memory
#define GET_MEM_LIMIT 67108864

#define GET_DATA	0
#define GET_FILE	1
#define GET_MEM		2
#define GET_MEM_FIX	3

#define GET_STATE_DEAD 		0
#define GET_STATE_INFO		1
#define GET_STATE_PROGRESS 	2
#define GET_STATE_ERROR 	3
#define GET_STATE_OK		4

typedef struct {
	unsigned int GetType;						// either GET_DATA, GET_FILE or GET_MEM, or GET_MEM_FIX
	unsigned int HttpResponseCode;				// response of the server
	unsigned int TotalBytes;					// bytes returned by the server
	unsigned int CurrentBytes;					// current bytes read, should equal TotalBytes when done
	float TimeStarted, TimeTaken;				// time this request started, and how much time its taken so far
	
	void *Internal;								// internal use, file pointer, whatever
	char *Mime;									// the mime type the server set, maybe null
	char *FileNameOrData;						// either the file written, or the bytes themselves
	unsigned int AllocatedBytes;				// bytes allocated for data if GET_MEMORY
	unsigned int InitialAllocation;				// our initial allocation of bytes for this memory object
	
	const char *Url;							// Current URL
	const char *Info;							// info, for like state update calls
	void *UserPointer;							// a user pointer for this particular get
	void (*StateUpdate)(void*,int);				// a user function to track what is happening with this object
} getObject;

typedef void (*getUserTrackerFunc)(void*,int);

#ifdef BUILD_DLL

#define EXPORT __declspec(dllexport)

EXPORT void getSetup();							// setup get internals
EXPORT void getCleanup();						// destroy get internals
EXPORT void getSetClient(const char *name);		// set client name, like Mozilla, whatever you want (user-agent)
EXPORT void getSetProxy(const char *proxy);		// define a proxy if we are using one: <type>://<address>:<port> (type is: http, socks4, socks5)
EXPORT void getSetInterface(const char *addr);	// what interface should we bind to for use? (ip or hostname)
EXPORT void getSetProxyUP(const char *up);		// <user>:<password> for http proxy
EXPORT void getSetRequestUP(const char *up);	// <user>:<password> for http requests
EXPORT getObject *getFileObject(const char *fname);		// create a file request object 
EXPORT getObject *getDataObject();						// create a data request object (head request only)
EXPORT getObject *getMemObject(int initial_buffer);		// create a mem request object
EXPORT getObject *getMemFixObject(int fixed_size);		// create a mem request object with fixed size
EXPORT void getSetUserPointer(getObject *p, void* user); 	// set the user pointer for this object
EXPORT void getSetTracker(getObject *p, getUserTrackerFunc f); 		// set the state update tracker for this object
EXPORT int getRequest(getObject *p, const char *url);	// request a document and store it in the given object 
EXPORT void getFree(getObject *p);				// free an allocated getObject
EXPORT void getSetDefaultUserPointer(void *user);		// default for all new objects
EXPORT void getSetDefaultTracker(getUserTrackerFunc f);	// default for all new objects

#else // BUILD_DLL

typedef struct {
	void* DllHandle;
	
	void (*SetClient)(const char*);
	void (*SetProxy)(const char*);
	void (*SetInterface)(const char*);
	void (*SetProxyUp)(const char*);
	void (*SetRequestUp)(const char*);
	getObject* (*FileObject)(const char*);
	getObject* (*DataObject)();
	getObject* (*MemObject)(int);
	getObject* (*MemFixObject)(int);
	void (*SetUserPointer)(getObject*,void*);
	void (*SetUserTracker)(getObject*,getUserTrackerFunc);
	int (*Request)(getObject*,const char *);
	void (*Free)(getObject*);
	void (*SetDefaultUserPointer)(void*);
	void (*SetDefaultTracker)(getUserTrackerFunc);
} getInterface;

#ifdef WIN32
	// define some dlfcn wrappers
	#ifndef WIN32_DLFCN_WRAPPED
	#define WIN32_DLFCN_WRAPPED
		#include <windows.h>
		void* dlopen(const char *fname, int ignored) { return (void*)LoadLibrary(fname); }
		void* dlsym(void*h,const char*s) { return (void*)GetProcAddress((HMODULE)h,s); }
		int dlclose(void*h) { return FreeLibrary((HMODULE)h); }
	#endif
#else
	#include <dlfcn.h>
#endif

	getInterface* getOpen(const char *fname) {
			getInterface *ret = (getInterface*)calloc(1,sizeof(getInterface));
			if (!ret) return ret;
			ret->DllHandle = dlopen(fname,0);
			if (!ret->DllHandle) return ret;
			
			void (*dof)();
			dof = dlsym(ret->DllHandle,"getSetup");
			dof();
			
			ret->SetClient = (void (*)(const char*))dlsym(ret->DllHandle,"getSetClient");
			ret->SetProxy = (void (*)(const char*))dlsym(ret->DllHandle,"getSetProxy");
			ret->SetInterface = (void (*)(const char*))dlsym(ret->DllHandle,"getSetInterface");
			ret->SetProxyUp = (void (*)(const char*))dlsym(ret->DllHandle,"getSetProxyUp");
			ret->SetRequestUp = (void (*)(const char*))dlsym(ret->DllHandle,"getSetRequestUp");
			ret->FileObject = (getObject* (*)(const char*))dlsym(ret->DllHandle,"getFileObject");
			ret->DataObject = (getObject* (*)())dlsym(ret->DllHandle,"getDataObject");
			ret->MemObject = (getObject* (*)(int))dlsym(ret->DllHandle,"getMemObject");
			ret->MemFixObject = (getObject* (*)(int))dlsym(ret->DllHandle,"getMemFixObject");
			ret->Request = (int (*)(getObject*,const char*))dlsym(ret->DllHandle,"getRequest");
			ret->Free = (void (*)(getObject*))dlsym(ret->DllHandle,"getFree");
			ret->SetDefaultUserPointer = (void (*)(void*))dlsym(ret->DllHandle,"getSetDefaultUserPointer");
			ret->SetDefaultTracker = (void (*)(getUserTrackerFunc))dlsym(ret->DllHandle,"getSetDefaultTracker");
	
			return ret;
		}
	int getOk(getInterface *p) { return p->DllHandle != 0; }
	void getClose(getInterface *p) {
			void (*dof)();
			dof = dlsym(p->DllHandle,"getCleanup");
			dof();
			
			dlclose(p->DllHandle);
			free(p);
		}

#endif // BUILD_DLL


#endif //safety

