// SHCSDK.cpp : DLL 응용 프로그램에 대한 진입점을 정의합니다.
//

#include <windows.h>
#include <atlenc.h>

#include <time.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>

#include <string>
#include <vector>
#include <set>
   
#include "CommLib.h"
#include "SHSSDK.h"
#include "SHCSDK.h"

#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h> 
#define  SET_CRT_DEBUG_FIELD(a)   _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else // _DEBUG
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif // _DEBUG


#ifndef off64_t
#define off64_t __int64
#endif

// dadamin del : #include "ne_socket.h"
// dadamin del : #include "ne_uri.h"
// dadamin del : #include "ne_request.h"
// dadamin del : #include "ne_xml.h"
// dadamin del : #include "ne_string.h"
// dadamin del : #include "ne_dates.h"

//#include "../Common/SBUtil.h"
#include <atlstr.h>
#include <atltime.h>

#pragma comment(lib, "ws2_32.lib")
//#pragma comment(lib, "libexpat.lib")

#include <direct.h>

using namespace std;

#define DELIMITER 0x1b

#define MAX_TRY    3
#define COUNT_SIZE 4
#define PATH_SIZE  2048
#define SOCK_TIMEOUT 5

typedef struct COMMLIB_HANDLE {
	//dadamin del : ne_session*  pnsess;
	//dadamin del : ne_uri       nuri;
	HSHSDK		 hsdk;
	string		 sUri;	
	string       sUserId;
	string       sPassword;
	string       sDavAuth;
	DWORD        dwError;
	string       sError;

	// 업/다운 관련
	HANDLE       hThread;
	HANDLE       hWaitEvent;
	UINT32       uJob;
	string       sJobParam;
	cl_callback  proc;
	void*        pParam;
	HANDLE       hTranFile;
	__int64		 nExFileSize;
	__int64      iTranPos;
	__int64      nFileSize;
	DWORD        dwOldTick;
	int          nTranStop;
	string       sRedirect;
	string		 sDomain2;

	set<PCLSERVICE_STRUCT>  setServiceList;
	set<PCLPATHINFO_STRUCT> setPathInfoList;
	set<PCLFILE_STRUCT>     setFileList;
} COMMLIB_STRUCT, *PCOMMLIB_STRUCT;

static enum {
	CLJOB_PUT = 0,
	CLJOB_GET,
};

static enum {
	CLSTOP_NO = 0,
	CLSTOP_BYUSER,
	CLSTOP_BYERROR,
};


BOOL StartTransfer(PCOMMLIB_STRUCT pcl);
static DWORD WINAPI ThreadProc(LPVOID lpParam);

// Socket command
//dadamin del : static bool DoCommand(PCOMMLIB_STRUCT pcl, LPCSTR pszService, int nCommand, LPVOID pSendBody, DWORD dwSendBodyLen, LPVOID* ppRecvBody, LPDWORD pdwRecvBodyLen);

#define COUNT_SIZE 4
#define PATH_SIZE  2048

// Webdav command
/*dadamin del : 
static bool DoCommand(PCOMMLIB_STRUCT pcl, LPCSTR pszMethod, LPCSTR pszPath, LPCSTR pszHeaders = NULL, LPCSTR pszBody = NULL,
	bool bParseBody = false, LPVOID pSTagParser = NULL, LPVOID pDataParser = NULL, LPVOID pETagParser = NULL, LPVOID pParam = NULL);
*/
//dadain del : static int ResponseBodyReader(void* userdata, const char* buf, size_t len);

static void    DoUpload(PCOMMLIB_STRUCT pcl);
// dadamin del : static ssize_t UploadProvider(void *userdata, char *buffer, size_t buflen);

static void DoDownload(PCOMMLIB_STRUCT pcl);
// dadamin del : static int  DownloadProvider(void* userdata, const char* buf, size_t len);

// dadamin del :static int FileListSTagParser(void *userdata, int parent, const char *nspace, const char *name, const char **atts);
// dadamin del :static int FileListDataParser(void *userdata, int state, const char *data, size_t len);
// dadamin del :static int FileListETagParser(void *userdata, int state, const char *nspace, const char *name);

static string GetErrorMessage(DWORD dwError);

/* dadamin del
static string PathEncode(LPCSTR pszPath);
static string PathDecode(LPCSTR pszPath);
static string URLEncode(LPCSTR pszURL);
static string URLDecode(LPCSTR pszURL);

static BOOL   DeleteDirectory(LPCSTR pszDirectory);
static string ConvertTimeFormat(LPCSTR pszTime);

static void   ReplaceAll(string& sValue, LPCSTR pszOld, LPCSTR pszNew);
static int _sh_send(SOCKET s, char *buf, int len);
static int _sh_recv(SOCKET s, char *buf, int len);

int GetCurrentPath(char* pszPath);
*/
typedef struct {
	int                    nTag;
	UINT                   nRootPathLen;
	PCLFILE_STRUCT         pclf;
	vector<PCLFILE_STRUCT> vec;
} CLFILELIST_PARSER_STRUCT, *PCLFILELIST_PARSER_STRUCT;

static enum {
	CLFLTAG_UNKNOWN = 0,
	CLFLTAG_PATH,
	CLFLTAG_TYPE,
	CLFLTAG_SIZE,
	CLFLTAG_LASTMODIFIED,
	CLFLTAG_SOURCE,
};


static HINSTANCE g_hInst = NULL;
static HANDLE g_hFile = NULL;

static HANDLE g_hLogFile = NULL;
static bool g_bWriteDirLog = true;
static bool g_bWriteUploadLog = true;

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
#ifdef  _DEBUG
	SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF );
	//_CrtSetBreakAlloc(235);
#endif
	g_hInst = (HINSTANCE)hModule;

	if (dwReason == DLL_PROCESS_ATTACH)
		g_hFile = CreateFile("C:\\CommLib.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
	else if (dwReason == DLL_PROCESS_DETACH)
		CloseHandle(g_hFile);
	
    return TRUE;
}

int __stdcall CallbackProc(void *param, INT64 result)
{
	PCOMMLIB_STRUCT pcl =  (PCOMMLIB_STRUCT) param;
	
	if(pcl && pcl->pParam && result != 0)
	{
		pcl->proc(pcl->pParam, result);
	}
	
	return  (pcl->nTranStop == CLSTOP_BYUSER ? 0 : 1);
}

#ifdef _OLD
WIN32DLL
HCOMMLIB cl_init(const char *url, const char *userId, const char *password, const char *proxyAddr, unsigned int proxyPort)
#else
WIN32DLL
HCOMMLIB cl_init(const char *url, const char *D2, const char *userId, const char *password, const char *proxyAddr, unsigned int proxyPort)
#endif
{
	PCOMMLIB_STRUCT pcl = NULL;
	CString strTemp;

//	strTemp.Format("cl_init : %s - %s - %s\n",url,userId,password);
//	OutputDebugString(strTemp);

	if(url == NULL || strlen(url) <= 0 )
		return NULL;

	pcl = new COMMLIB_STRUCT;

	if (!pcl)
		return NULL;

	char* astring = NULL;

	astring = (char*)sh_get_auth_sp_string(userId, password);
	
	if( astring == NULL )
	{
		// error
		delete pcl;
		pcl = NULL;
	}

	pcl->sUri = url;
	pcl->sUserId = userId;
	pcl->sPassword = password;
	pcl->sDavAuth = astring;
	pcl->sDomain2 = D2;

	pcl->dwError = 0;
	pcl->sError  = "";

	pcl->proc = NULL;
	pcl->pParam = NULL;
	
	// 업/다운 관련
	pcl->hThread    = NULL;
	pcl->hWaitEvent = NULL;


	sh_mem_free(astring);

	pcl->hsdk = sh_init(pcl->sUri.c_str(), pcl->sDavAuth.c_str(), CallbackProc, pcl);
	if (!pcl->hsdk)
	{
		// error
		delete pcl;
		pcl = NULL;
	}

	return pcl;
	/* dadamin del 
	pcl->pnsess = NULL;

	CString sUrl = CENTER_ADDR;

	if (url && strlen(url) > 0)
	{
		sUrl = url;
	}

	if(strlen(D2) == 0)
	{
		if (ne_sock_init() != NE_OK)
			goto EXIT_FUNCTION;
	}

	int nRet = ne_uri_parse(sUrl.GetBuffer(), &pcl->nuri);
//	strTemp.Format("%x : %s\n",pcl->nuri.host,pcl->nuri.host);
//	OutputDebugString(strTemp);

	if (nRet != NE_OK)
		goto EXIT_FUNCTION;

	if (!pcl->nuri.scheme)
		pcl->nuri.scheme = strdup("http");

	if (pcl->nuri.port == 0)
		pcl->nuri.port = 80;

	pcl->sUserId   = userId;
	pcl->sPassword = password;

	char szMD5[1024];
	ne_md5_buffer(password, szMD5);

	pcl->sDavAuth  = pcl->sUserId + ":";
	pcl->sDavAuth += szMD5;

	char* pszBase64 = (char*)ne_base64((const unsigned char*)pcl->sDavAuth.c_str(), pcl->sDavAuth.length());

	pcl->sDavAuth  = "Basic ";
	pcl->sDavAuth += pszBase64;
	pcl->sDomain2 = D2;

	free(pszBase64);

	pcl->pnsess = ne_session_create(pcl->nuri.scheme, pcl->nuri.host, pcl->nuri.port);
	if (!pcl->pnsess)
		goto EXIT_FUNCTION;

	if (proxyAddr != NULL && strlen(proxyAddr) > 0 && strlen(proxyAddr) > 0)
		ne_session_proxy(pcl->pnsess, proxyAddr, proxyPort);

	pcl->dwError = 0;
	pcl->sError  = "";

	// 업/다운 관련
	pcl->hThread    = NULL;
	pcl->hWaitEvent = NULL;

	return pcl;

EXIT_FUNCTION:
	DWORD dwError = GetLastError();

	if (pcl->nuri.scheme)
		ne_uri_free(&pcl->nuri);

	if (pcl->pnsess)
		ne_session_destroy(pcl->pnsess);

	delete pcl;

	SetLastError(dwError);
	*/
	return NULL;
}

WIN32DLL
void cl_free(HCOMMLIB hcl)
{
	if (!hcl)
		return;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	
	cl_stop_transfer(hcl);
	
	sh_free(pcl->hsdk);
	delete pcl;
	/* dadamin del
	cl_stop_transfer(hcl);

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;

	for (set<PCLSERVICE_STRUCT>::iterator iter = pcl->setServiceList.begin(); iter != pcl->setServiceList.end(); iter++)
		delete [](*iter);

	for (set<PCLPATHINFO_STRUCT>::iterator iter = pcl->setPathInfoList.begin(); iter != pcl->setPathInfoList.end(); iter++)
		delete [](*iter);

	for (set<PCLFILE_STRUCT>::iterator iter = pcl->setFileList.begin(); iter != pcl->setFileList.end(); iter++)
		delete [](*iter);

	if (pcl->hWaitEvent)
		CloseHandle(pcl->hWaitEvent);

	if (pcl->pnsess)
		ne_session_destroy(pcl->pnsess);

//	CString strTemp;
//	strTemp.Format("Delete : %x : %s",pcl->nuri.host,pcl->nuri.host);
//	OutputDebugString(strTemp);

	if (pcl->nuri.scheme)
		ne_uri_free(&pcl->nuri);

//	OutputDebugString("... Complete...\n");
	delete pcl;
	*/
}


WIN32DLL
int cl_get_error_number(HCOMMLIB hcl)
{
	if (!hcl)
		return CLERRNO_INVALID_HANDLE;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;

	return (int)pcl->dwError;
}

WIN32DLL
const char* cl_get_error_message(HCOMMLIB hcl)
{
	if (!hcl)
		return GetErrorMessage(CLERRNO_INVALID_HANDLE).c_str();

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;

	return pcl->sError.c_str();
}


WIN32DLL
PCLSERVICE_STRUCT cl_get_service_list(HCOMMLIB hcl, unsigned int *count)
{
	if (!hcl)
		return NULL;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	pcl->dwError = 0;
	pcl->sError  = "";

	if(!pcl->sUri.empty())
	{	
		string gtshost;
		int gtsport = 80;
		string::size_type cutAt = pcl->sUri.find(":");
		
		if(cutAt !=  pcl->sUri.npos)
		{
			gtshost = pcl->sUri.substr(0, cutAt);
			gtsport = atoi(pcl->sUri.substr(cutAt+1,pcl->sUri.size() - cutAt).c_str());
		}
		else 
		{
			gtshost = pcl->sUri;
		}

		sh_set_center_info(gtshost.c_str(), gtsport);
	}

	PCLSERVICE_STRUCT pclsl = NULL;

	pclsl = (PCLSERVICE_STRUCT) sh_get_service_list(pcl->sUserId.c_str(), 
												pcl->sPassword.c_str(),(int *) count);
		
	if (*count == 0) {
		pcl->dwError = GetLastError();
		pcl->sError  = GetErrorMessage(pcl->dwError);
		goto EXIT_FUNCTION;
	}

	//pclsl = new CLSERVICE_STRUCT[*count];
	//if (!pclsl) {
	//	pcl->dwError = GetLastError();
	//	pcl->sError  = GetErrorMessage(pcl->dwError);
	//	goto EXIT_FUNCTION;
	//}

	//for (UINT i = 0; i < *count; i++)
	//	memcpy(&pclsl[i], pbyBody + COUNT_SIZE + (sizeof(CLSERVICE_STRUCT) * i), sizeof(CLSERVICE_STRUCT));

	pcl->setServiceList.insert(pclsl);

EXIT_FUNCTION:

	return pclsl;
}

WIN32DLL
void cl_free_service_list(HCOMMLIB hcl, PCLSERVICE_STRUCT pclsl)
{
	if (!hcl || !pclsl)
		return;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;

	set<PCLSERVICE_STRUCT>::iterator iter = pcl->setServiceList.find(pclsl);
	if (iter == pcl->setServiceList.end())
		return;

	//delete []pclsl;
	sh_mem_free(pclsl);

	pcl->setServiceList.erase(pclsl);
}

WIN32DLL
BOOL cl_get_service_info(HCOMMLIB hcl, const char *serviceId, __int64 *totalBytes, __int64 *usedBytes)
{
	if (!hcl)
		return FALSE;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	pcl->dwError = 0;
	pcl->sError  = "";


	__int64 t = 0, f = 0;	

	string::size_type cutAt = pcl->sUserId.find("@");
	string userid = pcl->sUserId;
	if(cutAt !=  userid.npos)
	{
		userid = userid.substr(cutAt+1, userid.size() - cutAt);
	}

	if(sh_get_service_info(userid.c_str(), pcl->sPassword.c_str(), serviceId, &t, &f) != 1)
	{
		pcl->dwError = GetLastError();
		return FALSE;	
	}

	*totalBytes = t;
	*usedBytes = t - f;

	return TRUE;
	

	/* dadamin del
	PBYTE pbyBody   = NULL;
	DWORD dwBodyLen = 0;

	for (int i = 0; i < MAX_TRY; i++) {
		if (DoCommand(pcl, serviceId, 0x0012, NULL, 0, (LPVOID*)&pbyBody, &dwBodyLen))
			break;

		if (pcl->dwError != WSAETIMEDOUT || i == (MAX_TRY - 1))
			return FALSE;
	}


	BOOL bRet = FALSE;

	char szTotal[MAX_PATH];
	memcpy(szTotal, pbyBody, dwBodyLen);
	szTotal[dwBodyLen] = NULL;

	char* pszFree = strchr(szTotal, DELIMITER);
	*(pszFree++) = NULL;

	*totalBytes = _atoi64(szTotal);
	*usedBytes  = _atoi64(pszFree);

	bRet = TRUE;

//EXIT_FUNCTION:
	if (pbyBody)
		delete []pbyBody;

	return bRet;
	*/
}
WIN32DLL
PCLFILE_STRUCT cl_get_file_list(HCOMMLIB hcl, const char* path, unsigned int depth, unsigned int *count)
{
	if (!hcl)
		return NULL;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	pcl->dwError = 0;
	pcl->sError  = "";


	HSHFILELIST h = sh_get_filelist(pcl->hsdk, path, depth);
	if (h == 0 )
	{
		// error
		pcl->dwError = sh_get_error_number(pcl->hsdk);
		pcl->sError  = sh_get_error_message(pcl->hsdk);
		return NULL;
	}

	unsigned int nFileCount = sh_get_filelist_count(pcl->hsdk, h);

	PCLFILE_STRUCT pclf = NULL;

	if (nFileCount > 0) 
	{
		pclf = new CLFILE_STRUCT[nFileCount];
		for (unsigned int i = 0; i < nFileCount; i++) 
		{
			PSHFILE_STRUCT pshf = sh_get_file(pcl->hsdk, h, i);
			strcpy(pclf[i].path, pshf->path); 
			strcpy(pclf[i].lastModified, pshf->lastModified);
			pclf[i].attr = pshf->attr;
			strcpy(pclf[i].source, pshf->source);
			pclf[i].size = pshf->size;

			if (strcmp(pclf[i].path, "*myself*") == 0) {
				string sPath = path;
				if (sPath[0] != '/')
					sPath = '/' + sPath;
				strcpy(pclf[i].path, sPath.c_str());
			}
		}

		pcl->setFileList.insert(pclf);
		sh_free_filelist(pcl->hsdk, h);
	}

	if (count)
		*count = nFileCount;	

	return pclf;
	/* dadamin del
	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;

//	CString strTemp;
//	strTemp.Format("DDD : cl_get_file_list : %s, %s\n",pcl->nuri.host,path);
//	OutputDebugString(strTemp);

	pcl->dwError = 0;
	pcl->sError  = "";

	char szDepth[10];
	if (depth < 2)
		sprintf(szDepth, "%d", depth);
	else
		strcpy(szDepth, "infinity");

	string sHeaders = "Depth|";
	sHeaders += szDepth;

	string sBody = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
	sBody += "<D:propfind xmlns:D=\"DAV:\">";
	sBody += "<D:prop>";
	sBody += "<D:resourcetype/>";
	sBody += "<D:getcontentlength/>";
	sBody += "<D:getlastmodified/>";
	sBody += "<D:source/>";
	sBody += "</D:prop>";
	sBody += "</D:propfind>";

	CLFILELIST_PARSER_STRUCT clflp;
	clflp.pclf         = NULL;
	clflp.nRootPathLen = (UINT)strlen(pcl->nuri.path);

	PCLFILE_STRUCT pclf = NULL;
	for (int i = 0; i < MAX_TRY; i++) {
		if (DoCommand(pcl, "PROPFIND", path, sHeaders.c_str(), sBody.c_str(), true, FileListSTagParser, FileListDataParser, FileListETagParser, &clflp))
			break;
		if (pcl->dwError != WSAETIMEDOUT || i == (MAX_TRY - 1))
			goto EXIT_FUNCTION;
	}

	unsigned int nFileCount = (unsigned int)clflp.vec.size();
	if (nFileCount > 0) {
		pclf = new CLFILE_STRUCT[nFileCount];
		for (unsigned int i = 0; i < nFileCount; i++) {
			memcpy(&pclf[i], clflp.vec.at(i), sizeof(CLFILE_STRUCT));
			if (strcmp(pclf[i].path, "*myself*") == 0) {
				string sPath = path;
				if (sPath[0] != '/')
					sPath = '/' + sPath;
				strcpy(pclf[i].path, sPath.c_str());
			}
		}

		pcl->setFileList.insert(pclf);
	}

	if (count)
		*count = nFileCount;

EXIT_FUNCTION:
	for (vector<PCLFILE_STRUCT>::iterator iter = clflp.vec.begin(); iter != clflp.vec.end(); iter++)
		delete (*iter);

	return pclf;
	*/
}

/*
WIN32DLL
long cl_get_filelist_count(HCOMMLIB hcl, HSHFILELIST hshfl)
{
	if (!hshsdk)
		return -1;

	PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;

	if (!hshfl) {
		psdk->nError = SHCERRNO_INVALIDFLHDL;
		psdk->sError = GetErrorMessage(psdk->nError);
		return -1;
	}

	if (psdk->pvecshfl != hshfl) {
		set<PVECTOR_SHFILELIST>::iterator iter = psdk->setFileList.find((PVECTOR_SHFILELIST)hshfl);
		if (iter == psdk->setFileList.end()) {
			psdk->nError = SHCERRNO_INVALIDFLHDL;
			psdk->sError = GetErrorMessage(psdk->nError);
			return -1;
		}

		psdk->pvecshfl = (*iter);
	}

	return (long)psdk->pvecshfl->size();
}
*/

WIN32DLL
void cl_free_file_list(HCOMMLIB hcl, PCLFILE_STRUCT pclf)
{
	if (!hcl || !pclf)
		return;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;

	set<PCLFILE_STRUCT>::iterator iter = pcl->setFileList.find(pclf);
	if (iter == pcl->setFileList.end())
		return;

	delete []pclf;

	pcl->setFileList.erase(pclf);
}

WIN32DLL
PCLPATHINFO_STRUCT cl_get_path_auth(HCOMMLIB hcl, const char *serviceId, unsigned int *count)
{
	if (!hcl)
		return NULL;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	pcl->dwError = 0;
	pcl->sError  = "";
	
	string::size_type cutAt = pcl->sUserId.find("@");
	string userid = pcl->sUserId;
	if(cutAt !=  userid.npos)
	{
		userid = userid.substr(cutAt+1, userid.size() - cutAt);
	}

	PCLPATHINFO_STRUCT pclpi = NULL;
	int c = 0;
	char *p = (char *)sh_get_anonyauth(userid.c_str(), pcl->sPassword.c_str(),serviceId,  &c);
	
	*count = c;
	if (*count == 0) 
	{
		int err = sh_get_lasterror();
		if(err == 0)
		{
			pcl->dwError = CLERRNO_NOAVAILPATH_LIST;
			pcl->sError  = GetErrorMessage(pcl->dwError);
		}
		else 
		{
			if( err == SHERRNO_INTERNAL )
				err = CLERRNO_SERVICE;
			pcl->dwError = err;
			pcl->sError  = GetErrorMessage(pcl->dwError);
		}
	}
	else 
	{
		pclpi = new CLPATHINFO_STRUCT[*count];
		for (UINT i = 0; i < *count; i++)
			memcpy(pclpi[i].path, p + (PATH_SIZE * i), PATH_SIZE);

		pcl->setPathInfoList.insert(pclpi);
		sh_mem_free(p);
	}
	

	return pclpi;
	/* dadamin del 
	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	pcl->dwError = 0;
	pcl->sError  = "";

	PBYTE pbyBody   = NULL;
	DWORD dwBodyLen = 0;

	for (int i = 0; i < MAX_TRY; i++) {
		if (DoCommand(pcl, serviceId, 0x0030, NULL, 0, (LPVOID*)&pbyBody, &dwBodyLen))
			break;

		if (pcl->dwError != WSAETIMEDOUT || i == (MAX_TRY - 1))
			return NULL;
	}


	if (dwBodyLen == 0) {
		pcl->dwError = CLERRNO_ABNORMAL_RESPONSE;
		pcl->sError  = GetErrorMessage(pcl->dwError);
		return NULL;
	}

	memcpy(count, pbyBody, COUNT_SIZE);
	*count = ntohl(*count);

	PCLPATHINFO_STRUCT pclpi = NULL;
	if (*count == 0) {
		pcl->dwError = CLERRNO_NOAVAILPATH_LIST;
		pcl->sError  = GetErrorMessage(pcl->dwError);
		goto EXIT_FUNCTION;
	}

	pclpi = new CLPATHINFO_STRUCT[*count];
	if (!pclpi) {
		pcl->dwError = GetLastError();
		pcl->sError  = GetErrorMessage(pcl->dwError);
		goto EXIT_FUNCTION;
	}

	for (UINT i = 0; i < *count; i++)
		memcpy(pclpi[i].path, pbyBody + COUNT_SIZE + (PATH_SIZE * i), PATH_SIZE);

	pcl->setPathInfoList.insert(pclpi);

EXIT_FUNCTION:
	if (pbyBody)
		delete []pbyBody;

	return pclpi;
	*/
}

WIN32DLL
void cl_free_path_auth(HCOMMLIB hcl, PCLPATHINFO_STRUCT pclpi)
{
	if (!hcl || !pclpi)
		return;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;

	set<PCLPATHINFO_STRUCT>::iterator iter = pcl->setPathInfoList.find(pclpi);
	if (iter == pcl->setPathInfoList.end())
		return;

	delete []pclpi;

	pcl->setPathInfoList.erase(pclpi);
}

WIN32DLL
BOOL cl_set_anonyauth(HCOMMLIB hcl, const char *serviceName, BOOL set, const char *path)
{
	if (!hcl)
		return FALSE;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	pcl->dwError = 0;
	pcl->sError  = "";

	string::size_type cutAt = pcl->sUserId.find("@");
	string userid = pcl->sUserId;
	if(cutAt !=  userid.npos)
	{
		userid = userid.substr(cutAt+1, userid.size() - cutAt);
	}

	BOOL bRet = FALSE;

	string         sPath = path;
	vector<string> vecPath;

	int iString = 0;
	string::size_type stBegin = 0, stEnd = 0;
	do {
		stEnd   = sPath.find(',', stBegin);
		vecPath.push_back(sPath.substr(stBegin, stEnd - stBegin));
		stBegin = stEnd + 1;
	} while (stEnd != string::npos);

	int   nBodyLen = ((int)vecPath.size() * PATH_SIZE) + COUNT_SIZE;
	char* pszBody  = new char[nBodyLen];
	if (!pszBody) {
		pcl->dwError = GetLastError();
		pcl->sError  = GetErrorMessage(pcl->dwError);
		return FALSE;
	}
	memset(pszBody, NULL, nBodyLen);

	int nPathCount = htonl((u_long)vecPath.size());
	memcpy(pszBody, &nPathCount, COUNT_SIZE);

	for (UINT i = 0; i < vecPath.size(); i++)
		strcpy(pszBody + COUNT_SIZE + (PATH_SIZE * i), vecPath[i].c_str());

	bRet = TRUE;
	if( sh_set_anonyauth(userid.c_str(), pcl->sPassword.c_str(), serviceName, set, nBodyLen, pszBody ) != 1 )
	{
		//error
		pcl->dwError = GetLastError();
		pcl->sError  = GetErrorMessage(pcl->dwError);

		bRet = FALSE;		
	}

	if (pszBody)
		delete []pszBody;

	return bRet;

	/* dadamin del
	BOOL bRet = FALSE;

	string         sPath = path;
	vector<string> vecPath;

	int iString = 0;
	string::size_type stBegin = 0, stEnd = 0;
	do {
		stEnd   = sPath.find(',', stBegin);
		vecPath.push_back(sPath.substr(stBegin, stEnd - stBegin));
		stBegin = stEnd + 1;
	} while (stEnd != string::npos);

	int   nBodyLen = ((int)vecPath.size() * PATH_SIZE) + COUNT_SIZE;
	char* pszBody  = new char[nBodyLen];
	if (!pszBody) {
		pcl->dwError = GetLastError();
		pcl->sError  = GetErrorMessage(pcl->dwError);
		goto EXIT_FUNCTION;
	}
	memset(pszBody, NULL, nBodyLen);

	int nPathCount = htonl((u_long)vecPath.size());
	memcpy(pszBody, &nPathCount, COUNT_SIZE);

	for (UINT i = 0; i < vecPath.size(); i++)
		strcpy(pszBody + COUNT_SIZE + (PATH_SIZE * i), vecPath[i].c_str());
		
	for (int i = 0; i < MAX_TRY; i++) {
		if (DoCommand(pcl, serviceName, set ? 0x0014 : 0x0018, pszBody, nBodyLen, NULL, NULL))
			break;

		if (pcl->dwError != WSAETIMEDOUT || i == (MAX_TRY - 1))
			goto EXIT_FUNCTION;
	}

	bRet = TRUE;

EXIT_FUNCTION:
	if (pszBody)
		delete []pszBody;

	return bRet;
	*/
}

WIN32DLL
BOOL cl_set_bandwidth(HCOMMLIB hcl, const char *serviceName, const char *levelnpath)
{
	if (!hcl)
		return FALSE;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	pcl->dwError = 0;
	pcl->sError  = "";

	BOOL bRet = FALSE;
	return bRet;
	/* dadamin del 
	string         sLevelnPath = levelnpath;
	vector<string> vecLevel;
	vector<string> vecPath;

	int iString = 0;
	string::size_type stBegin = 0, stEnd = 0;
	do {
		stEnd   = sLevelnPath.find('|', stBegin);
		vecLevel.push_back(sLevelnPath.substr(stBegin, stEnd - stBegin));
		stBegin = stEnd + 1;

		stEnd   = sLevelnPath.find(',', stBegin);
		vecPath.push_back(sLevelnPath.substr(stBegin, stEnd - stBegin));
		stBegin = stEnd + 1;
	} while (stEnd != string::npos);

	int nPackedSize = COUNT_SIZE + PATH_SIZE;

	int   nBodyLen = COUNT_SIZE + ((int)vecPath.size() * nPackedSize);
	char* pszBody  = new char[nBodyLen];
	if (!pszBody) {
		pcl->dwError = GetLastError();
		pcl->sError  = GetErrorMessage(pcl->dwError);
		goto EXIT_FUNCTION;
	}
	memset(pszBody, NULL, nBodyLen);

	int nPathCount = htonl((u_long)vecPath.size());
	memcpy(pszBody, &nPathCount, COUNT_SIZE);

	for (UINT i = 0; i < vecPath.size(); i++) {
		int nLevel = htonl(atoi(vecLevel[i].c_str()));
		memcpy(pszBody + COUNT_SIZE + (nPackedSize * i), &nLevel, COUNT_SIZE);
		strcpy(pszBody + COUNT_SIZE + (nPackedSize * i) + COUNT_SIZE, vecPath[i].c_str());
	}

	for (int i = 0; i < MAX_TRY; i++) {
		if (DoCommand(pcl, serviceName, 0x001C, pszBody, nBodyLen, NULL, NULL))
			break;

		if (pcl->dwError != WSAETIMEDOUT || i == (MAX_TRY - 1))
			goto EXIT_FUNCTION;
	}

	bRet = TRUE;

EXIT_FUNCTION:
	if (pszBody)
		delete []pszBody;

	return bRet;
	*/
}

WIN32DLL
BOOL cl_make_directory(HCOMMLIB hcl, const char* directory)
{
	if (!hcl)
		return FALSE;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	pcl->dwError = 0;
	pcl->sError  = "";

	if( sh_make_directory(pcl->hsdk, directory) == 0 )
	{
		pcl->dwError = sh_get_error_number(pcl->hsdk);
		pcl->sError = sh_get_error_message(pcl->hsdk);
		return FALSE;
	}

	return TRUE;

	/* dadmain del
	for (int i = 0; i < MAX_TRY; i++) {
		if (DoCommand(pcl, "MKCOL", directory))
			break;

		if (pcl->dwError != WSAETIMEDOUT || i == (MAX_TRY - 1))
			return FALSE;
	}
	
	return TRUE;
	*/
}

WIN32DLL
BOOL cl_copy(HCOMMLIB hcl, const char* srcPath, const char* dstPath, BOOL overwrite)
{
	if (!hcl)
		return FALSE;
	
	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	pcl->dwError = 0;
	pcl->sError  = "";

	if( sh_copy(pcl->hsdk, srcPath, dstPath, overwrite) == 0 )
	{
		pcl->dwError = sh_get_error_number(pcl->hsdk);
		pcl->sError = sh_get_error_message(pcl->hsdk);
		return FALSE;
	}
	return TRUE;

	/* dadamin del
	string sDstPath = pcl->nuri.path;
	if (dstPath[0] != '/')
		sDstPath += "/";
	sDstPath += dstPath;

	string sHeaders = "New-uri|";
	sHeaders += PathEncode(sDstPath.c_str()) + ",Overwrite|";
	sHeaders += overwrite ? "T" : "F";

//	CString strTemp;

//	strTemp.Format("XXX COPY : %s - %s\n",srcPath,sHeaders.c_str());
//	OutputDebugString(strTemp);
	for (int i = 0; i < MAX_TRY; i++) {
		if (DoCommand(pcl, "COPY", srcPath, sHeaders.c_str()))
			break;

		if (pcl->dwError != WSAETIMEDOUT || i == (MAX_TRY - 1))
			return FALSE;
	}

	return TRUE;
	*/
}

WIN32DLL
BOOL cl_move(HCOMMLIB hcl, const char* srcPath, const char* dstPath, BOOL overwrite)
{
	if (!hcl)
		return FALSE;
	
	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	pcl->dwError = 0;
	pcl->sError  = "";

	if( sh_move(pcl->hsdk, srcPath, dstPath, overwrite) == 0 )
	{
		pcl->dwError = sh_get_error_number(pcl->hsdk);
		pcl->sError = sh_get_error_message(pcl->hsdk);
		return FALSE;
	}

	return TRUE;
	/*dadamin del
	string sDstPath = pcl->nuri.path;
	if (dstPath[0] != '/')
		sDstPath += "/";
	sDstPath += dstPath;

	string sHeaders = "New-uri|";
	//sHeaders += sDstPath + ",Overwrite|";
	sHeaders += PathEncode(sDstPath.c_str()) + ",Overwrite|";
	sHeaders += overwrite ? "T" : "F";

//	CString strTemp;

//	strTemp.Format("XXX cl_move : %s\n",srcPath);
//	OutputDebugString(strTemp);

	for (int i = 0; i < MAX_TRY; i++) {
		if (DoCommand(pcl, "MOVE", srcPath, sHeaders.c_str()))
			break;

		if (pcl->dwError != WSAETIMEDOUT || i == (MAX_TRY - 1))
			return FALSE;
	}

	return TRUE;
	*/
}

WIN32DLL
BOOL cl_delete(HCOMMLIB hcl, const char* path)
{
	if (!hcl)
		return FALSE;
	
	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	pcl->dwError = 0;
	pcl->sError  = "";

	if( sh_delete(pcl->hsdk, path) == 0 )
	{
		pcl->dwError = sh_get_error_number(pcl->hsdk);
		pcl->sError = sh_get_error_message(pcl->hsdk);
		return FALSE;
	}

	return TRUE;
	/* dadamin del 
	for (int i = 0; i < MAX_TRY; i++) {
		if (DoCommand(pcl, "DELETE", path))
			break;

		if (pcl->dwError != WSAETIMEDOUT || i == (MAX_TRY - 1))
			return FALSE;
	}
	
	return TRUE;
	*/
}

WIN32DLL
BOOL cl_upload(HCOMMLIB hcl, const char *srcPath, const char *dstPath, int writePolicy, __int64 availQuota, cl_callback callbackProc, void *pParam)
{
	if (!hcl)
		return FALSE;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;

//	CString strTemp;
//	OutputDebugString(strTemp);

	if (pcl->hThread) {
		pcl->dwError = CLERRNO_BUSY;
		pcl->sError  = GetErrorMessage(pcl->dwError);
		return FALSE;
	}

	pcl->dwError = 0;
	pcl->sError  = "";

	pcl->hTranFile   = INVALID_HANDLE_VALUE;
	pcl->iTranPos    = 0;
	pcl->dwOldTick   = 0;
	pcl->nTranStop   = CLSTOP_NO;

	pcl->sJobParam  = srcPath;
	pcl->sJobParam += "|";

	if (dstPath[0] != '/')
		pcl->sJobParam += "/";
	pcl->sJobParam += dstPath;
	pcl->sJobParam += "|";

	char szTemp[100];

	sprintf(szTemp, "%d", writePolicy);
	pcl->sJobParam += szTemp;
	pcl->sJobParam += "|";

	sprintf(szTemp, "%I64d", availQuota);
	pcl->sJobParam += szTemp;

	pcl->uJob   = CLJOB_PUT;
	pcl->proc   = callbackProc;
	pcl->pParam = pParam;

	pcl->dwOldTick = GetTickCount();

	return StartTransfer(pcl);
}

WIN32DLL
BOOL cl_download(HCOMMLIB hcl, const char *srcPath, const char *dstPath, int writePolicy, __int64 availQuota, cl_callback callbackProc, void *pParam)
{
	if (!hcl)
		return FALSE;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	if (pcl->hThread) {
		pcl->dwError = CLERRNO_BUSY;
		pcl->sError  = GetErrorMessage(pcl->dwError);
		return FALSE;
	}

	pcl->dwError = 0;
	pcl->sError  = "";

	pcl->hTranFile = INVALID_HANDLE_VALUE;
	pcl->iTranPos  = 0;
	pcl->dwOldTick = 0;
	pcl->nTranStop = CLSTOP_NO;
	
	pcl->sJobParam  = srcPath[0] != '/' ? "/" : "";
	pcl->sJobParam += srcPath;
	pcl->sJobParam += "|";

	pcl->sJobParam += dstPath;
	pcl->sJobParam += "|";

	char szTemp[100];

	sprintf(szTemp, "%d", writePolicy);
	pcl->sJobParam += szTemp;
	pcl->sJobParam += "|";

	sprintf(szTemp, "%I64d", availQuota);
	pcl->sJobParam += szTemp;

	pcl->uJob   = CLJOB_GET;
	pcl->proc   = callbackProc;
	pcl->pParam = pParam;

	pcl->dwOldTick = GetTickCount();

	return StartTransfer(pcl);
}

WIN32DLL
void cl_stop_transfer(HCOMMLIB hcl)
{
	if (!hcl)
		return;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)hcl;
	if (!pcl->hThread)
		return;

	pcl->nTranStop = CLSTOP_BYUSER;
	WaitForSingleObject(pcl->hWaitEvent, 10);
}

WIN32DLL 
void cl_set_write_log_dir(bool bLog)
{
	g_bWriteDirLog = bLog;
}

WIN32DLL 
void cl_set_write_log_upload(bool bLog)
{
	g_bWriteUploadLog = bLog;
}

WIN32DLL 
bool cl_create_log_file()
{
	if(g_hLogFile != INVALID_HANDLE_VALUE)
		CloseHandle(g_hLogFile);

	mkdir("c:\\TEMP\\");
	mkdir("c:\\TEMP\\SP-CONSOLE");

	g_hLogFile = CreateFile("C:\\TEMP\\SP-CONSOLE\\upload.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
	
	return g_hLogFile == INVALID_HANDLE_VALUE ? false : true;		
}

WIN32DLL
void cl_destroy_log_file()
{
	if(g_hLogFile != INVALID_HANDLE_VALUE)
		CloseHandle(g_hLogFile);

	g_hLogFile = INVALID_HANDLE_VALUE;
}

WIN32DLL void cl_write_log(char* pszLog, DWORD dwSize, bool bWriteTime)
{
	if(g_hLogFile == INVALID_HANDLE_VALUE)
		return;

	if(bWriteTime)
	{
		CTime time = CTime::GetCurrentTime();
		CString strTime = time.Format("[%Y-%m-%d %H:%M:%S] ");

		cl_write_log((LPTSTR)(LPCTSTR)strTime, strTime.GetLength(), false);
	}

	DWORD dwWritten = 0;
	bool bWritten = false;

	bWritten = WriteFile(g_hLogFile, pszLog, dwSize, &dwWritten, NULL) ? true : false;
	if(bWritten)
		FlushFileBuffers(g_hLogFile);
}
/* dadamin del
bool send(SOCKET s, LPCSTR pszBuf, int nLen);
bool recv(SOCKET s, LPSTR  pszBuf, int nLen);
*/

#pragma pack(1)
typedef struct {
	char    szTranId[52];
	__int32 nMode;
	char    szIssuer[128];
	char    szServiceId[128];
	__int32 nResult;
	__int32 nLength;
} COMMAND_STRUCT, PCOMMAND_STRUCT;
#pragma pack()

#define PRIVATE_KEY "I'm your father"
#define SERVER_NAME "SP-Console"

#define TRANSACTION_PORT 13104

unsigned long conv_addr(const char *name)
{
        struct hostent *he;
        int max;
        unsigned long retval;

        if ((retval = inet_addr(name)) != INADDR_NONE)
                return retval;

        he = gethostbyname(name);
        if (he == NULL)
                return INADDR_NONE;

        for (max = 0; he->h_addr_list[max]; max++) ;
        if (max == 1) return *((unsigned long *)(he->h_addr_list[0]));
        else return *((unsigned long *)(he->h_addr_list[rand() % max]));
}

/* dadamin del
static bool DoCommand(PCOMMLIB_STRUCT pcl, LPCSTR pszServiceId, int nCommand,
	LPVOID pSendBody, DWORD dwSendBodyLen, LPVOID* ppRecvBody, LPDWORD pdwRecvBodyLen)
{
	CString	strTemp;
	__time64_t time = _time64(NULL);
		
	
	srand((unsigned int)time);
	__int64 nRandom = rand() * rand();

	struct tm *tmNow = _localtime64(&time);

	time    %= 10000000000;	// MAX 10
	nRandom %= 10000000000;	// MAX 10

	char szMD5[256], szVerifyKey[256];
	sprintf(szMD5, "%010I64d%010I64d%s%s", time, nRandom, PRIVATE_KEY, SERVER_NAME);
	ne_md5_buffer(szMD5, szVerifyKey);

	char szPassword[128];
	strcpy(szMD5, pcl->sPassword.c_str());
	ne_md5_buffer(szMD5, szPassword);

	sprintf(szMD5, "%s%s%I64d", pcl->sUserId.c_str(), szPassword, time);
	ne_md5_buffer(szMD5, szPassword);

	char szAuth[256];
	sprintf(szAuth, "%s%c%s%c%I64d", pcl->sUserId.c_str(), DELIMITER, szPassword, DELIMITER, time);

	// Make header
	COMMAND_STRUCT cmd;
	memset(&cmd, NULL, sizeof(cmd));

	sprintf(cmd.szTranId, "%04d%02d%02d-%.10s-%010I64d-%010I64d",
		tmNow->tm_year, tmNow->tm_mon, tmNow->tm_wday, szVerifyKey, time, nRandom);
	cmd.nMode = htonl(nCommand);
	strcpy(cmd.szIssuer, SERVER_NAME);
	if (pszServiceId)
		strcpy(cmd.szServiceId, pszServiceId);
	cmd.nLength = htonl((u_long)strlen(szAuth) + dwSendBodyLen);


#ifdef _OLD
#else
	if (nCommand == 0x30 || nCommand == 0x12)
	{
		sprintf(pcl->nuri.host,"%s",pcl->sDomain2.c_str());
	}
#endif

// 	char szPort[MAX_PATH]={0};
// 	char szPath[MAX_PATH]={0};
// 	GetCurrentPath(szPath);
// 	strcat(szPath,"\\");
// 
// #ifdef _OPENDISK
// 	strcat(szPath,"OD-Console.ini");
// #else
// 	strcat(szPath,"KPClient.ini");
// #endif
// 
// 	GetPrivateProfileString("CONNECT", "TRCPORT", "", szPort, MAX_PATH, szPath);

// #ifdef _OLD
// 	if (pcl->nuri.port == 80)
// 	{
// 		if (strlen(szPort) > 0)
// 			pcl->nuri.port = atol(szPort);
// 		else
// 			pcl->nuri.port = TRANSACTION_PORT;
// 	}
// #else
	if ( nCommand == 0x12)
	{
// 		if (strlen(szPort) > 0)
// 			pcl->nuri.port = atol(szPort);
// 		else
			pcl->nuri.port = TRANSACTION_PORT;
 	}
// #endif

	// Send packet
	SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sock == INVALID_SOCKET) {
		pcl->dwError = WSAGetLastError();
		return false;
	}

	bool bRet = false;

	DWORD dwWritten;

//#endif

	char s[1024];

	sockaddr_in sa; 
	sa.sin_family      = AF_INET;
	sa.sin_addr.s_addr = conv_addr(pcl->nuri.host);
	sa.sin_port        = htons(pcl->nuri.port);

//	strTemp.Format("XXX CommLib : connect : %s, port= %d\n",inet_ntoa(sa.sin_addr),ntohs(sa.sin_port));

//	OutputDebugString(strTemp);

	int nNonBlocking = 1;
	ioctlsocket(sock, FIONBIO, (u_long FAR*)&nNonBlocking);

	if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) == SOCKET_ERROR)
	{
		if (WSAEWOULDBLOCK == WSAGetLastError())
		{
			fd_set wfd, efd;
			struct timeval tv;
			FD_ZERO(&wfd);
			FD_ZERO(&efd);
			FD_SET(sock, &wfd);
			FD_SET(sock, &efd);
			tv.tv_sec = SOCK_TIMEOUT;
			tv.tv_usec = 0;
			int nRecv = select(0, 0, &wfd, &efd,&tv);
			if (SOCKET_ERROR == nRecv || 0 == nRecv)
			{
				pcl->dwError = WSAGetLastError();
				goto EXIT_FUNCTION;
			}
		}
		else
		{
			sprintf(s, "[%08d] %09d> connect() failed!!!(ERROR:%d) EXIT!!!!!\n", GetCurrentThreadId(), GetTickCount(), WSAGetLastError());
			WriteFile(g_hFile, s, (DWORD)strlen(s), &dwWritten, NULL);

			pcl->dwError = WSAGetLastError();
			OutputDebugString("XXX CommLib : connect fail\n");
			goto EXIT_FUNCTION;
		}
	}
//	OutputDebugString("XXX CommLib : connect complete\n");
	
//	strTemp.Format("XXX CommLib : send : %s\n",inet_ntoa(sa.sin_addr));
//	OutputDebugString(strTemp);
	if (!_sh_send(sock, (char*)&cmd, sizeof(cmd))) {
		sprintf(s, "[%08d] %09d> send1() failed!!!(ERROR:%d) EXIT!!!!!\n", GetCurrentThreadId(), GetTickCount(), WSAGetLastError());
		WriteFile(g_hFile, s, (DWORD)strlen(s), &dwWritten, NULL);

		pcl->dwError = WSAGetLastError();
		OutputDebugString("XXX CommLib : send fail\n");
		goto EXIT_FUNCTION;
	}
//	OutputDebugString("XXX CommLib : send complete\n");

	if (dwSendBodyLen > 0) {
		DWORD dwAuthLen = (DWORD)strlen(szAuth);

		char* pszBody = new char[dwAuthLen + dwSendBodyLen];
		memcpy(pszBody,             szAuth,    dwAuthLen);
		memcpy(pszBody + dwAuthLen, pSendBody, dwSendBodyLen);

//		strTemp.Format("XXX CommLib : send : %s : %s\n",inet_ntoa(sa.sin_addr),pszBody);
//		OutputDebugString(strTemp);

		if (!_sh_send(sock, pszBody, dwAuthLen + dwSendBodyLen)) {
			sprintf(s, "[%08d] %09d> send2() failed!!!(ERROR:%d) EXIT!!!!!\n", GetCurrentThreadId(), GetTickCount(), WSAGetLastError());
			WriteFile(g_hFile, s, (DWORD)strlen(s), &dwWritten, NULL);

			delete []pszBody;

			pcl->dwError = WSAGetLastError();
			pcl->sError  = GetErrorMessage(pcl->dwError);
			goto EXIT_FUNCTION;
		}

		delete []pszBody;
	}
	else if (!_sh_send(sock, szAuth, (int)strlen(szAuth))) {
		sprintf(s, "[%08d] %09d> send2() failed!!!(ERROR:%d) EXIT!!!!!\n", GetCurrentThreadId(), GetTickCount(), WSAGetLastError());
		WriteFile(g_hFile, s, (DWORD)strlen(s), &dwWritten, NULL);

		pcl->dwError = WSAGetLastError();
		goto EXIT_FUNCTION;
	}

//	strTemp.Format("XXX CommLib : recv : %s\n",inet_ntoa(sa.sin_addr));
//	OutputDebugString(strTemp);
	if (!_sh_recv(sock, (char*)&cmd, sizeof(cmd))) {
		sprintf(s, "[%08d] %09d> recv1() failed!!!(ERROR:%d) EXIT!!!!!\n", GetCurrentThreadId(), GetTickCount(), WSAGetLastError());
		WriteFile(g_hFile, s, (DWORD)strlen(s), &dwWritten, NULL);

		pcl->dwError = WSAGetLastError();
		
		if (pcl->dwError == 0)
		{
			pcl->sError = "Recv 1 Fail : " + string((char*)&cmd);
		}

		OutputDebugString("XXX CommLib : recv fail 1\n");
		goto EXIT_FUNCTION;
	}
//	OutputDebugString("XXX CommLib : recv complete\n");

	cmd.nResult = ntohl(cmd.nResult);
	if (cmd.nResult != 0x1000)
	{
		OutputDebugString("XXX CommLib : Invalid cmd.Result\n");
		if(cmd.nResult == 0)
			pcl->dwError = WSAGetLastError();
		else
			pcl->dwError = cmd.nResult;
		goto EXIT_FUNCTION;
	}
 
	cmd.nLength = ntohl(cmd.nLength);
	if (ppRecvBody && cmd.nLength > 0) {
		*pdwRecvBodyLen = cmd.nLength;
		*ppRecvBody     = new char[*pdwRecvBodyLen];
		if (!(*ppRecvBody))
		{
			OutputDebugString("XXX CommLib : Mem Alloc Fail\n");
			pcl->dwError = GetLastError();
			goto EXIT_FUNCTION;
		}

		if (!_sh_recv(sock, (char*)*ppRecvBody, *pdwRecvBodyLen)) {
			delete [](*ppRecvBody);

			sprintf(s, "[%08d] %09d> recv2() failed!!!(ERROR:%d) EXIT!!!!!\n", GetCurrentThreadId(), GetTickCount(), WSAGetLastError());
			WriteFile(g_hFile, s, (DWORD)strlen(s), &dwWritten, NULL);

			OutputDebugString("XXX CommLib : recv fail 2\n");
			pcl->dwError = WSAGetLastError();
			goto EXIT_FUNCTION;
		}
	}
		
	bRet = true;

EXIT_FUNCTION:
	if (pcl->dwError > 0)
	{
		switch (pcl->dwError)
		{
		case 0x3000:
			pcl->dwError = CLERRNO_ABNORMAL_RESPONSE;
			break;
		case 0x3001:
			pcl->dwError = CLERRNO_AUTHORIZATION;
			break;
		case 0x9000:
			pcl->dwError = CLERRNO_SERVICE;
			break;
		}
		pcl->sError = GetErrorMessage(pcl->dwError);
	}

	if (sock != INVALID_SOCKET)
		closesocket(sock);

	return bRet;	
}
*/
/* dadamin del
bool send(SOCKET s, LPCSTR pszBuf, int nLen)
{
	int iSent = 0, nSentLen;
	do {
		nSentLen = send(s, pszBuf + iSent, nLen, 0);

		iSent += nSentLen;
		nLen  -= nSentLen;
	} while (nLen > 0 && nSentLen > 0);

	return (nLen == 0);
}

bool recv(SOCKET s, LPSTR pszBuf, int nLen)
{
	int iRecv = 0, nRecvLen;
	do {
		nRecvLen = recv(s, pszBuf + iRecv, nLen, 0);

		iRecv += nRecvLen;
		nLen  -= nRecvLen;
	} while (nLen > 0 && nRecvLen > 0);

	return (nLen == 0);
}
*/
/* dadamin del
static bool DoCommand(PCOMMLIB_STRUCT pcl, LPCSTR pszMethod, LPCSTR pszPath, LPCSTR pszHeaders, LPCSTR pszBody,
	bool bParseBody, LPVOID pSTagParser, LPVOID pDataParser, LPVOID pETagParser, LPVOID pParam)
{
	
	string sPath = pcl->nuri.path;
	if (pszPath[0] != '/')
		sPath += "/";
	sPath += pszPath;

	CString strMethod = pszMethod;
	if(g_bWriteDirLog && strMethod == "MKCOL")
	{
		CString strLog;
		strLog.Format(_T("Request creation directory : Host(\"%s\"), Method(\"%s\"), Path(\"%s\")\r\n"), pcl->nuri.host, strMethod, sPath.c_str());
		cl_write_log((LPTSTR)(LPCTSTR)strLog, strLog.GetLength(), true);
	}

	bool   bRet = false;
	int    nRet;
	string sBody;
//	CString	strTemp;

//	strTemp.Format("XXX CommLib : DoCommand %s - %s - %s - %s\n",pcl->nuri.host,pszMethod,pcl->nuri.path,pszPath);
//	OutputDebugString(strTemp);

	ne_request *pnreq = ne_request_create(pcl->pnsess, pszMethod, PathEncode(sPath.c_str()).c_str());
	if (!pnreq) {
		pcl->dwError = GetLastError();
		pcl->sError  = ne_get_error(pcl->pnsess);
		OutputDebugString("XXX CommLib : Error : ne_request_create\n");
		goto EXIT_FUNCTION;
	}
	
	ne_add_request_header(pnreq, "Authorization", pcl->sDavAuth.c_str());
	ne_add_request_header(pnreq, "Cache-Control", "no-cache");
	if (pszHeaders && strlen(pszHeaders) > 0) {
		string sHeaders = pszHeaders;

		string::size_type stBegin = 0, stEnd = 0;
		do {
			stEnd = sHeaders.find(',', stBegin);

			string sHeader = sHeaders.substr(stBegin, stEnd - stBegin);

			string::size_type stDivider = sHeader.find('|');
			ne_add_request_header(pnreq, sHeader.substr(0, stDivider).c_str(), sHeader.substr(stDivider + 1, sHeader.length()).c_str());

			stBegin = stEnd + 1;
		} while (stEnd != string::npos);
	}

	if (pszBody && strlen(pszBody) > 0)
		ne_set_request_body_buffer(pnreq, pszBody, strlen(pszBody));

	if (bParseBody)
		ne_add_response_body_reader(pnreq, ne_accept_2xx, ResponseBodyReader, &sBody);

	nRet = ne_request_dispatch(pnreq);
	if (nRet != NE_OK) 
	{
		pcl->dwError = nRet;
		pcl->sError  = ne_get_error(pcl->pnsess);
		CString strTemp;
		strTemp.Format("XXX CommLib : Error : ne_request_dispatch, Message : %s\r\n", pcl->sError.c_str());
		OutputDebugString(strTemp);

		if(g_bWriteDirLog && strMethod == "MKCOL")
			cl_write_log((LPTSTR)(LPCTSTR)strTemp, strTemp.GetLength(), true);
		
		goto EXIT_FUNCTION;
	}

	ne_status* pnstat = (ne_status*)ne_get_status(pnreq);
	if (pnstat->code != 0 && (pnstat->code < 200 || pnstat->code >= 300)) {
		pcl->dwError = pnstat->code;
		pcl->sError  = ne_get_error(pcl->pnsess);
		CString strTemp;
		strTemp.Format("XXX CommLib : ne_get_status, Error : ne_get_status : %s\n",pcl->sError.c_str());
		OutputDebugString(strTemp);

		if(g_bWriteDirLog && strMethod == "MKCOL")
			cl_write_log((LPTSTR)(LPCTSTR)strTemp, strTemp.GetLength(), true);

		goto EXIT_FUNCTION;
	}

	if (bParseBody) {
		ReplaceAll(sBody, "&amp;", "*amp;");

		ne_xml_parser* pnxparser = ne_xml_create();
		ne_xml_push_handler(pnxparser, (ne_xml_startelm_cb*)pSTagParser, (ne_xml_cdata_cb*)pDataParser, (ne_xml_endelm_cb*)pETagParser, pParam);
		ne_xml_parse(pnxparser, sBody.c_str(), sBody.length());
		ne_xml_destroy(pnxparser);
	}

	bRet = true;

	if(g_bWriteDirLog && strMethod == "MKCOL")
	{
		CString strLog;
		strLog.Format(_T("Response creation directory : Path(\"%s\"), Return code(%ld)\r\n"), sPath.c_str(), pcl->dwError);
		cl_write_log((LPTSTR)(LPCTSTR)strLog, strLog.GetLength(), true);
	}

EXIT_FUNCTION:
	bool bError = false;
	CString strErrorCode;

	switch (pcl->dwError) 
	{
	case 400:
		bError = true;
		strErrorCode = "CLERRNO_ABNORMAL_RESPONSE";
		pcl->dwError = CLERRNO_ABNORMAL_RESPONSE;
		pcl->sError  = GetErrorMessage(pcl->dwError);
		break;
	case 401:
		bError = true;
		strErrorCode = "CLERRNO_AUTHORIZATION";
		pcl->dwError = CLERRNO_AUTHORIZATION;
		pcl->sError  = GetErrorMessage(pcl->dwError);
		break;
	case 403:
		bError = true;
		strErrorCode = "CLERRNO_FORBIDDEN";
		pcl->dwError = CLERRNO_FORBIDDEN;
		pcl->sError  = GetErrorMessage(pcl->dwError);
		break;
	case 404:
		bError = true;
		strErrorCode = "CLERRNO_NOEXISTSFILE";

		pcl->sRedirect = ne_get_response_header(pnreq, "Redirect") != NULL ? ne_get_response_header(pnreq, "Redirect") : "";
		pcl->dwError = CLERRNO_NOEXISTSFILE;
		pcl->sError  = GetErrorMessage(pcl->dwError);
		break;
	case 500:
		bError = true;
		strErrorCode = "CLERRNO_SERVICE";
        pcl->dwError = CLERRNO_SERVICE;
		pcl->sError  = GetErrorMessage(pcl->dwError);
		break;
	}

	if(bError && g_bWriteDirLog && strMethod == "MKCOL")
	{
		CString strLog;
		strLog.Format(_T("Error : %s(%ld), %s\r\n"), strErrorCode, pcl->dwError, pcl->sError.c_str());
		cl_write_log((LPTSTR)(LPCTSTR)strLog, strLog.GetLength(), true);
	}

	if (pnreq)
		ne_request_destroy(pnreq);

	return bRet;	
}
*/

BOOL StartTransfer(PCOMMLIB_STRUCT pcl)
{
	if (!pcl->hWaitEvent) {
		pcl->hWaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		if (!pcl->hWaitEvent) {
			pcl->dwError = GetLastError();
			pcl->sError  = GetErrorMessage(pcl->dwError);
			return FALSE;
		}
	}

	pcl->hThread = CreateThread(NULL, 0, ThreadProc, pcl, 0, NULL);
	if (!pcl->hThread) {
		pcl->dwError = GetLastError();
		pcl->sError  = GetErrorMessage(pcl->dwError);
		return FALSE;
	}

	return TRUE;
}

static DWORD WINAPI ThreadProc(LPVOID lpParam)
{
	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)lpParam;

	switch (pcl->uJob) {
	case CLJOB_PUT:
/*
		DoUpload(pcl);
*/
		for (int i = 0; i < MAX_TRY; i++) {
			pcl->hTranFile = NULL;
			DoUpload(pcl);
			if (pcl->hTranFile)
				CloseHandle(pcl->hTranFile);

			if (pcl->dwError != WSAETIMEDOUT || i == (MAX_TRY - 1))
				break;
		}
		break;
	case CLJOB_GET:
/*
		DoDownload(pcl);
*/
		for (int i = 0; i < MAX_TRY; i++) {
			pcl->hTranFile = NULL;
			DoDownload(pcl);

			if (pcl->hTranFile)
			{
				SetFilePointerEx(pcl->hTranFile, (LARGE_INTEGER&)pcl->iTranPos, NULL, FILE_BEGIN);
				SetEndOfFile(pcl->hTranFile);
				CloseHandle(pcl->hTranFile);
			}

			if (pcl->dwError != WSAETIMEDOUT || i == (MAX_TRY - 1))
				break;
		}
		break;
	}

	if (pcl->nTranStop == CLSTOP_BYUSER)
		SetEvent(pcl->hWaitEvent);

	pcl->proc(pcl->pParam, pcl->dwError != 0 ? -1 : 0);

	CloseHandle(pcl->hThread);
	pcl->hThread = NULL;

	return 0;
}

static void DoUpload(PCOMMLIB_STRUCT pcl)
{
	// 현재 URI 보관
	bool   bFindSource    = true;
	bool   bSessionChange = false;

	pcl->dwError = 0;
	pcl->sError  = "";

	// 업로드 코드 시작
	string  sSrcObj, sDstObj;
	int     nRet, nWritePolicy;
	__int64 nAvailQuota;

	int iString = 0;
	string::size_type stBegin = 0, stEnd = 0;
	do {
		stEnd = pcl->sJobParam.find('|', stBegin);

		switch (iString++) {
		case 0:
			sSrcObj = pcl->sJobParam.substr(stBegin, stEnd - stBegin);
			break;
		case 1:
			sDstObj = pcl->sJobParam.substr(stBegin, stEnd - stBegin);
			break;
		case 2:
			nWritePolicy = atoi(pcl->sJobParam.substr(stBegin, stEnd - stBegin).c_str());
			break;
		case 3:
			nAvailQuota = _atoi64(pcl->sJobParam.substr(stBegin, stEnd - stBegin).c_str());
			break;
		}

		stBegin = stEnd + 1;
	} while (stEnd != string::npos);

	CString str = "1234";
	if( sh_upload(pcl->hsdk, sSrcObj.c_str(), sDstObj.c_str(), nWritePolicy, nAvailQuota, str) == 0)
	{
		pcl->dwError = sh_get_error_number(pcl->hsdk);
		pcl->sError  = sh_get_error_message(pcl->hsdk);
		return;
	}

	return;
	/* dadamin del
	ne_uri nuri = pcl->nuri;

	// 업로드 코드 시작
	string  sSrcObj, sDstObj;
	int     nRet, nWritePolicy;
	__int64 nAvailQuota;

	int iString = 0;
	string::size_type stBegin = 0, stEnd = 0;
	do {
		stEnd = pcl->sJobParam.find('|', stBegin);

		switch (iString++) {
		case 0:
			sSrcObj = pcl->sJobParam.substr(stBegin, stEnd - stBegin);
			break;
		case 1:
			sDstObj = pcl->sJobParam.substr(stBegin, stEnd - stBegin);
			break;
		case 2:
			nWritePolicy = atoi(pcl->sJobParam.substr(stBegin, stEnd - stBegin).c_str());
			break;
		case 3:
			nAvailQuota = _atoi64(pcl->sJobParam.substr(stBegin, stEnd - stBegin).c_str());
			break;
		}

		stBegin = stEnd + 1;
	} while (stEnd != string::npos);

	string sPath = pcl->nuri.path + sDstObj;
	string sHeaders;

	CString strPath = sPath.c_str();

	ne_request *pnreq = NULL;

	sPath = PathEncode(sPath.c_str());

	pcl->hTranFile = CreateFile(sSrcObj.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (pcl->hTranFile == INVALID_HANDLE_VALUE) {
		pcl->dwError = GetLastError();
		pcl->sError  = GetErrorMessage(pcl->dwError);
		return;
	}

	LARGE_INTEGER liFileSize, liFilePos = {0, 0};
	if (!GetFileSizeEx(pcl->hTranFile, &liFileSize)) {
		pcl->dwError = GetLastError();
		pcl->sError  = GetErrorMessage(pcl->dwError);
		goto EXIT_FUNCTION;
	}

	if(g_bWriteUploadLog)
	{
		CString strLog;
		strLog.Format(_T("Request Upload : Host(\"%s\"), Source(\"%s\" - %ld bytes), "), pcl->nuri.path, sSrcObj.c_str(), liFileSize);
		cl_write_log((LPTSTR)(LPCTSTR)strLog, strLog.GetLength(), true);			

		strLog.Format(_T("Target(\"%s\")\r\n"), strPath);
		cl_write_log((LPTSTR)(LPCTSTR)strLog, strLog.GetLength(), false);

	}

	if (nWritePolicy == CLWRITEPOLICY_OVERWRITE) 
	{
		PCLFILE_STRUCT pclf = cl_get_file_list((HCOMMLIB)pcl, sDstObj.c_str(), 0, NULL);
		if (pclf) {
			cl_free_file_list((HCOMMLIB)pcl, pclf);

			if (!cl_delete((HCOMMLIB)pcl, sDstObj.c_str()))
				goto EXIT_FUNCTION;
		}
	}
	else if (nWritePolicy == CLWRITEPOLICY_APPEND) {
		PCLFILE_STRUCT pclf = cl_get_file_list((HCOMMLIB)pcl, sDstObj.c_str(), 0, NULL);
		if (pclf) {
			if (liFileSize.QuadPart <= pclf->size) {
				cl_free_file_list((HCOMMLIB)pcl, pclf);
				goto EXIT_FUNCTION;
			}

			LARGE_INTEGER liNewPos;
			liNewPos.QuadPart = pclf->size;
			if (!SetFilePointerEx(pcl->hTranFile, liNewPos, &liFilePos, FILE_BEGIN)) {
				cl_free_file_list((HCOMMLIB)pcl, pclf);
				goto EXIT_FUNCTION;
			}

			char szRange[100];
			sprintf(szRange, "bytes %I64d-%I64d/%I64d", liFilePos.QuadPart, liFileSize.QuadPart - 1, liFileSize.QuadPart);

			sHeaders  = "Content-Range|";
			sHeaders += szRange;

			if (strlen(pclf->source) > 7) {
				bSessionChange = true;
				ne_session_destroy(pcl->pnsess);

				ne_uri_parse(pclf->source, &pcl->nuri);

				if (pcl->nuri.path)
					free(pcl->nuri.path);
				pcl->nuri.path = strdup("/dav");

				if (!pcl->nuri.scheme)
					pcl->nuri.scheme = strdup("http");

				if (pcl->nuri.port == 0)
					pcl->nuri.port = 80;

				pcl->pnsess = ne_session_create(pcl->nuri.scheme, pcl->nuri.host, pcl->nuri.port);
			}

			cl_free_file_list((HCOMMLIB)pcl, pclf);

			bFindSource = false;
		}
	}
	else {
		PCLFILE_STRUCT pclf = cl_get_file_list((HCOMMLIB)pcl, sDstObj.c_str(), 0, NULL);
		if (pclf) {
			cl_free_file_list((HCOMMLIB)pcl, pclf);

			pcl->dwError = CLERRNO_EXISTSFILE;
			pcl->sError  = GetErrorMessage(pcl->dwError);
			goto EXIT_FUNCTION;
		}
		//cl_free_file_list((HCOMMLIB)pcl, pclf);
	}

	if ((UINT64)nAvailQuota < (UINT64)(liFileSize.QuadPart - liFilePos.QuadPart)) 
	{
		pcl->dwError = CLERRNO_NOAVAILQUOTA;
		pcl->sError  = GetErrorMessage(pcl->dwError);

		if(g_bWriteUploadLog)
		{
			CString strLog;
			strLog.Format(_T("Error : %s(CLERRNO_NOAVAILQUOTA)\r\n"), pcl->sError.c_str());
			cl_write_log((LPTSTR)(LPCTSTR)strLog, strLog.GetLength(), true);			
		}

		goto EXIT_FUNCTION;
	}

	if (bFindSource) 
	{
		for (int i = 0; !bSessionChange && i < MAX_TRY; i++) 
		{
			PCLFILE_STRUCT pclf = cl_get_file_list((HCOMMLIB)pcl, sDstObj.c_str(), 0, NULL);
			if (pclf) 
			{
				cl_free_file_list((HCOMMLIB)pcl, pclf);
				pcl->dwError = CLERRNO_ABNORMAL_RESPONSE;
				pcl->sError  = GetErrorMessage(pcl->dwError);

				if(g_bWriteUploadLog)
				{
					CString strLog;
					strLog.Format(_T("Error : %s(CLERRNO_ABNORMAL_RESPONSE)\r\n"), pcl->sError.c_str());
					cl_write_log((LPTSTR)(LPCTSTR)strLog, strLog.GetLength(), true);			
				}

				goto EXIT_FUNCTION;
			}

			if (pcl->sRedirect == "")
				break;
 
			if (i > 0)
				ne_uri_free(&pcl->nuri);
			bSessionChange = true;
			ne_session_destroy(pcl->pnsess);

			ne_uri_parse(pcl->sRedirect.c_str(), &pcl->nuri);

			if (!pcl->nuri.scheme)
				pcl->nuri.scheme = strdup("http");
			if (pcl->nuri.port == 0)
				pcl->nuri.port = 80;
			pcl->pnsess = ne_session_create(pcl->nuri.scheme, pcl->nuri.host, pcl->nuri.port);
			if (i == (MAX_TRY - 1)) {
				sHeaders = "Force|YES";
				break;
			}
		}
	}
	pnreq = ne_request_create(pcl->pnsess, "PUT", sPath.c_str());
	if (!pnreq) 
	{
		pcl->dwError = CLERRNO_UNDEFINED;
		pcl->sError  = ne_get_error(pcl->pnsess);

		if(g_bWriteUploadLog)
		{
			CString strLog;
			strLog.Format(_T("Error : %s(CLERRNO_UNDEFINED)\r\n"), pcl->sError.c_str());
			cl_write_log((LPTSTR)(LPCTSTR)strLog, strLog.GetLength(), true);			
		}

		goto EXIT_FUNCTION;
	}

	ne_add_request_header(pnreq, "Authorization", pcl->sDavAuth.c_str());
	if (sHeaders.length() > 0) {
		stBegin = 0, stEnd = 0;
		do {
			stEnd = sHeaders.find(',', stBegin);

			string sHeader = sHeaders.substr(stBegin, stEnd - stBegin);

			string::size_type stDivider = sHeader.find('|');
			ne_add_request_header(pnreq, sHeader.substr(0, stDivider).c_str(), sHeader.substr(stDivider + 1, sHeader.length()).c_str());

			stBegin = stEnd + 1;
		} while (stEnd != string::npos);
	}

	ne_set_request_body_provider64(pnreq, liFileSize.QuadPart - liFilePos.QuadPart, UploadProvider, pcl);
	pcl->iTranPos  = liFilePos.QuadPart;
	pcl->nFileSize = liFileSize.QuadPart;

	pcl->dwError = 0;
	pcl->sError  = "";
	nRet = ne_request_dispatch(pnreq);

	if (pcl->nTranStop == CLSTOP_NO) 
	{
		if (nRet != NE_OK) 
		{
			pcl->dwError = nRet;
			pcl->sError  = ne_get_error(pcl->pnsess);

			if(g_bWriteUploadLog)
			{
				CString strLog;
				strLog.Format(_T("Stop : %s(CLSTOP_NO)\r\n"), pcl->sError.c_str());
				cl_write_log((LPTSTR)(LPCTSTR)strLog, strLog.GetLength(), true);			
			}
			goto EXIT_FUNCTION;
		}

		ne_status* pnstat = (ne_status*)ne_get_status(pnreq);
		if (pnstat->code != 0 && (pnstat->code < 200 || pnstat->code >= 300)) 
		{
			pcl->dwError = pnstat->code;
			pcl->sError  = ne_get_error(pcl->pnsess);

			if(g_bWriteUploadLog)
			{
				CString strLog;
				strLog.Format(_T("Response Error : Code(%ld), Message(\"%s\")\r\n"), pcl->dwError, pcl->sError.c_str());
				cl_write_log((LPTSTR)(LPCTSTR)strLog, strLog.GetLength(), true);			
			}
			
			goto EXIT_FUNCTION;
		}
		else
		{
			if(g_bWriteUploadLog)	
			{
				CString strLog;
				strLog.Format(_T("Response Success : Code(%ld)\r\n"), pnstat->code);
				cl_write_log((LPTSTR)(LPCTSTR)strLog, strLog.GetLength(), true);			
			}
		}
	}
	ne_end_request(pnreq);

EXIT_FUNCTION:
	if (pcl->hTranFile) {
		CloseHandle(pcl->hTranFile);
		pcl->hTranFile = INVALID_HANDLE_VALUE;
	}

	if (pnreq)
		ne_request_destroy(pnreq);

	if (bSessionChange) {
        ne_uri_free(&pcl->nuri);

		pcl->nuri = nuri;
		pcl->pnsess = ne_session_create(pcl->nuri.scheme, pcl->nuri.host, pcl->nuri.port);
	}
	*/
}

static void DoDownload(PCOMMLIB_STRUCT pcl)
{
	string  sSrcObj, sDstObj;
	int     nRet, nWritePolicy;
	__int64 nAvailQuota;

	pcl->dwError = 0;
	pcl->sError  = "";

	int iString = 0;
	string::size_type stBegin = 0, stEnd = 0;
	do {
		stEnd = pcl->sJobParam.find('|', stBegin);

		switch (iString++) {
		case 0:
			sSrcObj = pcl->sJobParam.substr(stBegin, stEnd - stBegin);
			break;
		case 1:
			sDstObj = pcl->sJobParam.substr(stBegin, stEnd - stBegin);
			break;
		case 2:
			nWritePolicy = atoi(pcl->sJobParam.substr(stBegin, stEnd - stBegin).c_str());
			break;
		case 3:
			nAvailQuota = _atoi64(pcl->sJobParam.substr(stBegin, stEnd - stBegin).c_str());
			break;
		}

		stBegin = stEnd + 1;
	} while (stEnd != string::npos);

	if( sh_download(pcl->hsdk, sSrcObj.c_str(), sDstObj.c_str(), nWritePolicy, nAvailQuota, NULL) == 0 )
	{
		pcl->dwError = sh_get_error_number(pcl->hsdk);
		pcl->sError  = sh_get_error_message(pcl->hsdk);
		return;
	}

	return;
	/* dadamin del
	string sPath = pcl->nuri.path + sSrcObj;
	string sHeaders;

	ne_request *pnreq = NULL;

	sPath = PathEncode(sPath.c_str());

	DWORD dwCreationDisposition = OPEN_ALWAYS;
	DWORD dwAttr = GetFileAttributes(sDstObj.c_str());
	if (nWritePolicy == CLWRITEPOLICY_NONE) {
		if (dwAttr != INVALID_FILE_ATTRIBUTES || GetLastError() != ERROR_FILE_NOT_FOUND) {
			pcl->dwError = CLERRNO_EXISTSFILE;
			pcl->sError  = GetErrorMessage(pcl->dwError);
			return;
		}
		dwCreationDisposition = CREATE_NEW;
	}
	else {
		if (dwAttr != INVALID_FILE_ATTRIBUTES) {
			if (dwAttr & FILE_ATTRIBUTE_DIRECTORY) {
				if (nWritePolicy == CLWRITEPOLICY_OVERWRITE) {
					if (!DeleteDirectory(sDstObj.c_str())) {
						pcl->dwError = GetLastError();
						pcl->sError  = GetErrorMessage(pcl->dwError);
						return;
					}
				}
				else {
					pcl->dwError = CLERRNO_EXISTSFILE;
					pcl->sError  = GetErrorMessage(pcl->dwError);
				}
			}
			else {
				if (nWritePolicy == CLWRITEPOLICY_OVERWRITE)
					dwCreationDisposition = TRUNCATE_EXISTING;
			}
		}
	}

	PCLFILE_STRUCT pclf = cl_get_file_list((HCOMMLIB)pcl, sSrcObj.c_str(), 0, NULL);
	if (!pclf) {
		cl_free_file_list((HCOMMLIB)pcl, pclf);
		return;
	}

	LARGE_INTEGER liFilePos = {0, 0};

	if (pcl->hTranFile == NULL)
	{
		pcl->hTranFile = CreateFile(sDstObj.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
		if (pcl->hTranFile == INVALID_HANDLE_VALUE) {
			pcl->dwError = GetLastError();
			pcl->sError  = GetErrorMessage(pcl->dwError);
			goto EXIT_FUNCTION;
		}

		pcl->nExFileSize=0;
		GetFileSizeEx(pcl->hTranFile,(LARGE_INTEGER*)&pcl->nExFileSize);

		if (pcl->nExFileSize >= pclf->size) {
			pcl->dwError = 0;
			pcl->sError  = "";
			goto EXIT_FUNCTION;
		}

		LARGE_INTEGER new_size;
		new_size.QuadPart=pclf->size;
		SetFilePointerEx(pcl->hTranFile,new_size,NULL, FILE_BEGIN);
		SetEndOfFile(pcl->hTranFile);
		new_size.QuadPart=0;
		SetFilePointerEx(pcl->hTranFile,new_size,NULL, FILE_BEGIN);
	}

	if (nWritePolicy == CLWRITEPOLICY_APPEND) {
		LARGE_INTEGER liNewPos;
		liNewPos.QuadPart = 0;

		if (!SetFilePointerEx(pcl->hTranFile, (LARGE_INTEGER&)pcl->nExFileSize, &liFilePos, FILE_BEGIN)) {
			pcl->dwError = GetLastError();
			pcl->sError  = GetErrorMessage(pcl->dwError);
			goto EXIT_FUNCTION;
		}

		char szRange[100];

		sprintf(szRange, "bytes=%I64d-%I64d", liFilePos.QuadPart, pclf->size);
		sHeaders += "Range|";
		sHeaders += szRange;
		sHeaders += ",Accept-Ranges|bytes";
	}

	if ((UINT64)nAvailQuota < (UINT64)(pclf->size - liFilePos.QuadPart)) {
		pcl->dwError = CLERRNO_NOAVAILQUOTA;
		pcl->sError  = GetErrorMessage(pcl->dwError);
		goto EXIT_FUNCTION;
	}

	pnreq = ne_request_create(pcl->pnsess, "GET", sPath.c_str());
	if (!pnreq) {
		pcl->dwError = CLERRNO_UNDEFINED;
		pcl->sError  = ne_get_error(pcl->pnsess);
		goto EXIT_FUNCTION;
	}

	ne_add_request_header(pnreq, "Authorization", pcl->sDavAuth.c_str());
	if (sHeaders.length() > 0) {
		stBegin = 0, stEnd = 0;
		do {
			stEnd = sHeaders.find(',', stBegin);

			string sHeader = sHeaders.substr(stBegin, stEnd - stBegin);

			string::size_type stDivider = sHeader.find('|');
			ne_add_request_header(pnreq, sHeader.substr(0, stDivider).c_str(), sHeader.substr(stDivider + 1, sHeader.length()).c_str());

			stBegin = stEnd + 1;
		} while (stEnd != string::npos);
	}

	ne_add_response_body_reader(pnreq, ne_accept_2xx, DownloadProvider, pcl);
	pcl->iTranPos  = liFilePos.QuadPart;
	pcl->nFileSize = pclf->size;

	pcl->dwError = 0;
	pcl->sError  = "";

	nRet = ne_request_dispatch(pnreq);
	if (pcl->nTranStop == CLSTOP_NO) {
		if (nRet != NE_OK) {
			pcl->dwError = nRet;
			pcl->sError  = ne_get_error(pcl->pnsess);
			goto EXIT_FUNCTION;
		}

		ne_status* pnstat = (ne_status*)ne_get_status(pnreq);
		if (pnstat->code != 0 && (pnstat->code < 200 || pnstat->code >= 300)) {
			pcl->dwError = pnstat->code;
			pcl->sError  = ne_get_error(pcl->pnsess);
			goto EXIT_FUNCTION;
		}
	}
	ne_end_request(pnreq);

EXIT_FUNCTION:
	cl_free_file_list((HCOMMLIB)pcl, pclf);

	string sRedirection;
	if (pnreq) {
		const char *pszLocation = ne_get_response_header(pnreq, "Location");
		if (pszLocation)
			sRedirection = pszLocation;
		ne_request_destroy(pnreq);
	}

	// Redirection
	if (pcl->dwError == 301 && sRedirection != "") {
		if (nWritePolicy == CLWRITEPOLICY_NONE) {
			pcl->sJobParam  = sSrcObj;
			pcl->sJobParam += "|";

			pcl->sJobParam += sDstObj;
			pcl->sJobParam += "|";

			char szTemp[100];
			sprintf(szTemp, "%d", CLWRITEPOLICY_OVERWRITE);
			pcl->sJobParam += szTemp;
			pcl->sJobParam += "|";

			sprintf(szTemp, "%I64d", nAvailQuota);
			pcl->sJobParam += szTemp;
		}

		ne_session_destroy(pcl->pnsess);
		ne_uri nuri = pcl->nuri;

		// 지정된 곳으로 접속
		ne_uri_parse(sRedirection.c_str(), &pcl->nuri);

		if (!pcl->nuri.scheme)
			pcl->nuri.scheme = strdup("http");

		if (pcl->nuri.port == 0)
			pcl->nuri.port = 80;

		strcpy(pcl->nuri.path, nuri.path);

		pcl->pnsess = ne_session_create(pcl->nuri.scheme, pcl->nuri.host, pcl->nuri.port);

		DoDownload(pcl);

		// 원래 서버로 재접속
		ne_uri_free(&pcl->nuri);
		ne_session_destroy(pcl->pnsess);

		pcl->nuri = nuri;
		pcl->pnsess = ne_session_create(pcl->nuri.scheme, pcl->nuri.host, pcl->nuri.port);
	}
	*/
}

/*dadmain del : 
static int ResponseBodyReader(void* userdata, const char* buf, size_t len)
{
	if (len == 0)
		return 0;

	string* psBody = (string*)userdata;

	char* pszTemp = new char[len + 1];
	memcpy(pszTemp, buf, len);
	pszTemp[len] = NULL;

	(*psBody) += pszTemp;

	delete []pszTemp;
	
	return NE_OK;
}
*/

/* dadamin del
#define TERM_TICKCOUNT 500

static ssize_t UploadProvider(void *userdata, char *buffer, size_t buflen)
{
	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)userdata;

	if (buflen == 0)
		return 0;

	if (pcl->nTranStop == CLSTOP_BYUSER) {
		pcl->proc(pcl->pParam, pcl->iTranPos);
		return -1;
	}

	DWORD dwRead;

	if (!ReadFile(pcl->hTranFile, buffer, (DWORD)buflen, &dwRead, NULL)) {
		pcl->nTranStop = CLSTOP_BYERROR;

		pcl->dwError = GetLastError();
		pcl->sError  = GetErrorMessage(pcl->dwError);
		return -1;
	}

	pcl->iTranPos += dwRead;

	if (GetTickCount() > pcl->dwOldTick + TERM_TICKCOUNT || pcl->iTranPos >= pcl->nFileSize) {
		pcl->proc(pcl->pParam, pcl->iTranPos);
		pcl->dwOldTick = GetTickCount();
	}
	return dwRead;
}
*/
/*dadamin del
static int DownloadProvider(void* userdata, const char* buf, size_t len)
{
	//if (rand()%2)
	//	Sleep(50);
	//return 0;

	PCOMMLIB_STRUCT pcl = (PCOMMLIB_STRUCT)userdata;

	if (len == 0)
		return 0;

	if (pcl->nTranStop == CLSTOP_BYUSER) {
		pcl->proc(pcl->pParam, pcl->iTranPos);
		return 1;
	}

	DWORD dwWritten, dwTotal = 0;
	do {
		if (!WriteFile(pcl->hTranFile, buf + dwTotal, (DWORD)len - dwTotal, &dwWritten, NULL)) {
			pcl->nTranStop = CLSTOP_BYERROR;

			pcl->dwError = GetLastError();
			pcl->sError  = GetErrorMessage(pcl->dwError);
			return 1;
		}

		dwTotal += dwWritten;
	} while (dwTotal < len);

	pcl->iTranPos += dwTotal;

	if (GetTickCount() > pcl->dwOldTick + TERM_TICKCOUNT || pcl->iTranPos >= pcl->nFileSize) {
		pcl->proc(pcl->pParam, pcl->iTranPos);
		pcl->dwOldTick = GetTickCount();
	}

	return NE_OK;
}

static int FileListSTagParser(void *userdata, int parent, const char *nspace, const char *name, const char **atts)
{
	PCLFILELIST_PARSER_STRUCT pclflp = (PCLFILELIST_PARSER_STRUCT)userdata;

	if (strcmp(name, "response") == 0) {
		pclflp->pclf = new CLFILE_STRUCT;
		memset(pclflp->pclf, NULL, sizeof(CLFILE_STRUCT));
	}
	else if (strcmp(name, "href") == 0) {
		pclflp->nTag = CLFLTAG_PATH;
	}
	else if (strcmp(name, "collection") == 0) {
		pclflp->pclf->attr = CLFILEATTR_FOLDER;
	}
	else if (strcmp(name, "getcontentlength") == 0) {
		pclflp->nTag = CLFLTAG_SIZE;
	}
	else if (strcmp(name, "getlastmodified") == 0) {
		pclflp->nTag = CLFLTAG_LASTMODIFIED;
	}
//	else if (strcmp(name, "xxx") == 0) {
//		pclflp->nTag = CLFLTAG_MIMETYPE;
//	}
	else if (strcmp(name, "source") == 0) {
		pclflp->nTag = CLFLTAG_SOURCE;
	}
	else {
		pclflp->nTag = CLFLTAG_UNKNOWN;
	}

	return 1;
}

static int FileListDataParser(void *userdata, int state, const char *data, size_t len)
{
	PCLFILELIST_PARSER_STRUCT pclflp = (PCLFILELIST_PARSER_STRUCT)userdata;

	switch (pclflp->nTag) {
	case CLFLTAG_PATH:
		if (!pclflp->pclf->path[0]) {
			if (len >= pclflp->nRootPathLen) {
				int  nPathLen = (int)len - pclflp->nRootPathLen;
				char szPath[PATH_SIZE];
				memcpy(szPath, data + pclflp->nRootPathLen, nPathLen);
				szPath[nPathLen - (nPathLen > 1 && szPath[nPathLen - 1] == '/' ? 1 : 0)] = NULL;

				string sPath = PathDecode(szPath).c_str();
				strcpy(pclflp->pclf->path, sPath.c_str());
			}
			else {
				strcpy(pclflp->pclf->path, "*myself*");
			}
		}
		break;
	case CLFLTAG_TYPE:
		break;
	case CLFLTAG_SIZE:
		if (isdigit(data[0])) {
			char szSize[20];
			memcpy(szSize, data, len);
			szSize[len] = NULL;

			pclflp->pclf->size = _atoi64(szSize);
		}
		break;
	case CLFLTAG_LASTMODIFIED:
		if (!pclflp->pclf->lastModified[0]) {
			char szTime[30];
			memcpy(szTime, data, len);
			szTime[len] = NULL;

			string sTime = ConvertTimeFormat(szTime);
			strcpy(pclflp->pclf->lastModified, sTime.c_str());
		}
		break;
//	case CLFLTAG_MIMETYPE:
//		if (!pclflp->pclf->mimeType) {
//			pclflp->pclf->mimeType = new char[len + 1];
//			memcpy(pclflp->pclf->mimeType, data, len);
//			pclflp->pclf->mimeType[len] = NULL;
//		}
//		break;
	case CLFLTAG_SOURCE:
		if (!pclflp->pclf->source[0]) {
			char szSource[PATH_SIZE];
			memcpy(szSource, data, len);
			szSource[len] = NULL;

			strcpy(pclflp->pclf->source, szSource);
		}
		break;
	default:
		break;
	}

	return 0;
}

static int FileListETagParser(void *userdata, int state, const char *nspace, const char *name)
{
	PCLFILELIST_PARSER_STRUCT pclflp = (PCLFILELIST_PARSER_STRUCT)userdata;

	if (strcmp(name, "response") == 0) {
		if (pclflp->pclf)
			pclflp->vec.push_back(pclflp->pclf);

		pclflp->pclf = NULL;
	}

	return 0;
}
*/

static string GetErrorMessage(DWORD dwError)
{
	string sError;

	if (dwError >= CLERRNO_UNDEFINED && dwError <= CLERRNO_MAX) {
		char szError[1000];
		::LoadString(g_hInst, dwError, szError, sizeof(szError));

		sError = szError;
	}
	else {
		LPVOID lpError;

		if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpError, 0, NULL))
			sError = "알 수 없는 오류입니다.";
		else
			sError = (LPCSTR)lpError;
	 
		LocalFree(lpError);
	}

	return sError;
}

/* dadamin del
#define BUFFER_SIZE 1024

static string PathEncode(LPCSTR pszPath)
{
	if (pszPath[0] == '/')
		pszPath += 1;

	string sRetPath = "";
	string sSrcPath = pszPath;

	string::size_type stBegin = 0, stEnd = 0;
	do {
		stEnd = sSrcPath.find('/', stBegin);

		sRetPath += "/" + URLEncode(sSrcPath.substr(stBegin, stEnd - stBegin).c_str());

		stBegin = stEnd + 1;
	} while (stEnd != std::string::npos);

	return sRetPath;
}

static string PathDecode(LPCSTR pszPath)
{
	if (pszPath[0] == '/')
		pszPath += 1;

	string sRetPath = "";
	string sSrcPath = pszPath;

	string::size_type stBegin = 0, stEnd = 0;
	do {
		stEnd = sSrcPath.find('/', stBegin);

		sRetPath += "/" + URLDecode(sSrcPath.substr(stBegin, stEnd - stBegin).c_str());

		stBegin = stEnd + 1;
	} while (stEnd != std::string::npos);

	ReplaceAll(sRetPath, "*amp;", "&");

	return sRetPath;
}

static string URLEncode(LPCSTR pszURL)
{
	char  szEncoded[MAX_PATH << 1];
	char* pszEncoded = szEncoded;

	while (*pszURL != NULL) {
		if ((*pszURL >= 'a' && *pszURL <= 'z') || (*pszURL >= 'A' && *pszURL <= 'Z')
			|| (*pszURL >= '0' && *pszURL <= '9') || *pszURL == '/')
			*pszEncoded = (char)*pszURL;
		else {
			*pszEncoded++ = '%';

			char szBuf[10];
			sprintf(szBuf, "%02X", *pszURL);
			int nBufLen = (int)strlen(szBuf);
			*pszEncoded++ = szBuf[nBufLen - 2];
			*pszEncoded   = szBuf[nBufLen - 1];
		}

		pszEncoded++;
		pszURL++;
	}
	*pszEncoded = NULL;

	string sRet = szEncoded;

	return sRet;
}

static string URLDecode(LPCSTR pszURL)
{
	char szOut[BUFFER_SIZE], szHex[3];

	ZeroMemory(szOut, sizeof(szOut));

	for (int i = 0, j = 0; pszURL[i]; i++, j++) {
//		if (pszURL[i] == '+')
//			szOut[j] = ' ';
//		else if (pszURL[i] == '%') {
		if (pszURL[i] == '%') {
			szHex[0] = pszURL[++i];
			szHex[1] = pszURL[++i];
			szHex[2] = 0;
			sscanf((char *)szHex, "%x", &szOut[j]);
		} else {
			szOut[j] = pszURL[i];
		}
	}

	string sRet = szOut;

	return sRet;
}

static BOOL DeleteDirectory(LPCSTR pszDirectory)
{
	string sDirectory = pszDirectory;
	sDirectory += "\\*";

	WIN32_FIND_DATA w32fd;

	HANDLE hFindFile = FindFirstFile(sDirectory.c_str(), &w32fd);
	while (hFindFile != INVALID_HANDLE_VALUE) {
		if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
			if (w32fd.cFileName[0] != '.') {
				if (!DeleteDirectory(w32fd.cFileName))
					return false;
			}
		}
		else {
			if (!DeleteFile(w32fd.cFileName))
				return false;
		}

		if (!FindNextFile(hFindFile, &w32fd))
			break;
	}

	FindClose(hFindFile);

	return RemoveDirectory(pszDirectory);
}

// format : Thu, 15 Dec 2005 05:22:33 GMT
static string ConvertTimeFormat(LPCSTR pszTime)
{
	string sTime; 

	// RFC1123_FORMAT to time_t format & GMT+9(32400 sec)
	// "Thu, 15 Dec 2005 05:22:33 GMT" 이런 형태를 RFC1122_FORMAT 이라한다.
	// RFC1122_FORMAT 포맷을 인자로 넘겨서 time_t를 얻을 수 있었고, 
	// 얻은 값에다가 9시간에 해당하는 sec를 더해서 GMT+9를 구한다.
	time_t t = 0;// dadmain del : ne_rfc1123_parse(pszTime) + 32400;

	// time_t to struct tm
	// 위 과정에서 이미 GMT+9가 처리되었으므로,
	// 기존 소스처럼 복잡한 과정을 거치지 않아도 된다. 
	// 단지 time_t 값을 속성을 알고 year에 1900을 mon1을 더해준다.
	struct tm stm;
	stm = *gmtime(&t);
	stm.tm_year = stm.tm_year + 1900;
	stm.tm_mon = stm.tm_mon + 1;

	// 최종적으로 표현하고자 하는 날짜 포맷으로 변경처리한다.
	char szTemp[20];
	sprintf(szTemp, "%04d-%02d-%02d ", stm.tm_year, stm.tm_mon, stm.tm_mday);
	sTime = szTemp;
	sprintf(szTemp, " %02d:%02d:%02d", stm.tm_hour, stm.tm_min, stm.tm_sec);
	sTime += szTemp;

	return sTime;
}

static void ReplaceAll(string& sValue, LPCSTR pszOld, LPCSTR pszNew)
{
	string sOld = pszOld;
	string sNew = pszNew;

	size_t s;
	while ((s = sValue.find(sOld)) != string::npos)
		sValue.replace(s, sOld.length(), sNew);
}

int GetCurrentPath(char* pszPath)
{
	char	szPath[MAX_PATH*2]={0};
	char* pData;

	GetModuleFileName(NULL,szPath,MAX_PATH);

	pData = strrchr(szPath,'\\');

	__w64 int len = pData-szPath;
	strncpy(pszPath,szPath,len);
	pszPath[len] = 0; //cause wcsncpy does not appent null character
	return (int)len;
}

static int _sh_send(SOCKET s, char *pszBuf, int nLen)
{
	int iSent = 0, nSentLen;
	fd_set wset;
	struct timeval tv;

	FD_ZERO(&wset);
	FD_SET(s, &wset);
	tv.tv_sec = SOCK_TIMEOUT;
	tv.tv_usec = 0;
	do {
		if (select(static_cast<int>(s + 1), NULL, &wset, NULL, &tv) < 0) break;
		if (!FD_ISSET(s, &wset)) break;

		nSentLen = send(s, pszBuf + iSent, nLen, 0);

		iSent += nSentLen;
		nLen  -= nSentLen;
	} while (nLen > 0 && nSentLen > 0);

	return nLen > 0 ? SOCKET_ERROR : iSent;
}

static int _sh_recv(SOCKET s, char *pszBuf, int nLen)
{
	int iRecv = 0, nRecvLen;
	fd_set rset;
	struct timeval tv;
	int nRet;

	FD_ZERO(&rset);
	FD_SET(s, &rset);
	tv.tv_sec = SOCK_TIMEOUT;
	tv.tv_usec = 0;
	do {
		nRet = select(static_cast<int>(s + 1), &rset, NULL, NULL, &tv);
		
		if (nRet <= 0)
		{
			break;
		}
		if (!FD_ISSET(s, &rset)) break;

		nRecvLen = recv(s, pszBuf + iRecv, nLen, 0);

		iRecv += nRecvLen;
		nLen  -= nRecvLen;
	} while (nLen > 0 && nRecvLen > 0);

	return nLen < 0 ? SOCKET_ERROR : iRecv;
}
*/
