#include "Mra.h"
#include "MraFilesQueue.h"
#include "proto.h"




#define MRA_FT_HELLO	"MRA_FT_HELLO"
#define MRA_FT_GET_FILE	"MRA_FT_GET_FILE"



typedef struct
{
	LIST_MT			lmtListMT;
	DWORD			dwSendTimeOutInterval;
} MRA_FILES_QUEUE;



struct MRA_FILES_QUEUE_FILE
{
	LPWSTR		lpwszName;
	SIZE_T		dwNameLen;
	DWORDLONG	dwSize;
};




typedef struct
{
	// internal
	LIST_MT_ITEM			lmtListMTItem;
	BOOL					bIsWorking;
	DWORD					dwSendTime;
	// external
	DWORD					dwIDRequest;
	DWORD					dwFlags;
	HANDLE					hContact;
	DWORDLONG				dwFilesCount;
	DWORDLONG				dwFilesTotalSize;
	MRA_FILES_QUEUE_FILE	*pmfqfFiles;
	LPWSTR					pwszFilesList;
	LPWSTR					pwszDescription;
	MRA_ADDR_LIST			malAddrList;
	LPWSTR					lpwszPath;
	SIZE_T					dwPathSize;
	BOOL					bSending;
	HANDLE					hConnection;
	HANDLE					hListen;
	HANDLE					hThread;
	HANDLE					hWaitHandle;
	HANDLE					hMraMrimProxyData;

} MRA_FILES_QUEUE_ITEM;



struct MRA_FILES_THREADPROC_PARAMS
{
	HANDLE					hFilesQueueHandle;
	MRA_FILES_QUEUE_ITEM	*pmrafqFilesQueueItem;
};



//#define MEMALLOC(Size)		HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(Size+sizeof(SIZE_T)))
//#define MEMREALLOC(Mem,Size)	HeapReAlloc(GetProcessHeap(),(HEAP_ZERO_MEMORY),(LPVOID)Mem,(Size+sizeof(SIZE_T)))
//#define MEMFREE(Mem)			if (Mem) {HeapFree(GetProcessHeap(),0,(LPVOID)Mem);Mem=NULL;}


DWORD			MraFilesQueueItemFindByID			(HANDLE hFilesQueueHandle,DWORD dwIDRequest,MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem);
//DWORD			MraFilesQueueItemFindByEMail		(HANDLE hFilesQueueHandle,LPSTR lpszEMail,SIZE_T dwEMailSize,MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem);
void			MraFilesQueueItemFree				(MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem);
SIZE_T			MraFilesQueueGetLocalAddressesList	(LPSTR lpszBuff,SIZE_T dwBuffSize,DWORD dwPort);

BOOL			MraFilesQueueHandCheck				(HANDLE hConnection,MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem);
void			MraFilesQueueConnectionReceived		(HANDLE hNewConnection,DWORD dwRemoteIP,void *pExtra);

void			MraFilesQueueRecvThreadProc			(LPVOID lpParameter);
void			MraFilesQueueSendThreadProc			(LPVOID lpParameter);



void MraFilesQueueDlgEnableDirectConsControls(HWND hWndDlg,BOOL bEnabled)
{
	WORD wMraFilesControlsList[]={
							IDC_FILE_SEND_NOOUTCONNECTIONONRECEIVE,
							IDC_FILE_SEND_NOOUTCONNECTIONONSEND,
							IDC_FILE_SEND_IGNORYADDITIONALPORTS,
							IDC_FILE_SEND_HIDE_MY_ADDRESSES,
							IDC_FILE_SEND_ADD_EXTRA_ADDRESS,
							IDC_FILE_SEND_EXTRA_ADDRESS
	};
	EnableControlsArray(hWndDlg,(WORD*)&wMraFilesControlsList,SIZEOF(wMraFilesControlsList),bEnabled);
	EnableWindow(GetDlgItem(hWndDlg,IDC_FILE_SEND_EXTRA_ADDRESS),(bEnabled && IS_DLG_BUTTON_CHECKED(hWndDlg,IDC_FILE_SEND_ADD_EXTRA_ADDRESS)));
}

INT_PTR CALLBACK MraFilesQueueDlgProcOpts(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg){
	case WM_INITDIALOG:
		{
			WCHAR szBuff[MAX_PATH];

			TranslateDialogDefault(hWndDlg);

			CHECK_DLG_BUTTON(hWndDlg,IDC_FILE_SEND_ENABLE_DIRECT_CONN,DB_Mra_GetByte(NULL,"FileSendEnableDirectConn",MRA_DEF_FS_ENABLE_DIRECT_CONN));
			CHECK_DLG_BUTTON(hWndDlg,IDC_FILE_SEND_NOOUTCONNECTIONONRECEIVE,DB_Mra_GetByte(NULL,"FileSendNoOutConnOnRcv",MRA_DEF_FS_NO_OUT_CONN_ON_RCV));
			CHECK_DLG_BUTTON(hWndDlg,IDC_FILE_SEND_NOOUTCONNECTIONONSEND,DB_Mra_GetByte(NULL,"FileSendNoOutConnOnSend",MRA_DEF_FS_NO_OUT_CONN_ON_SEND));
			CHECK_DLG_BUTTON(hWndDlg,IDC_FILE_SEND_IGNORYADDITIONALPORTS,DB_Mra_GetByte(NULL,"FileSendIgnoryAdditionalPorts",MRA_DEF_FS_IGNORY_ADDITIONAL_PORTS));
			CHECK_DLG_BUTTON(hWndDlg,IDC_FILE_SEND_HIDE_MY_ADDRESSES,DB_Mra_GetByte(NULL,"FileSendHideMyAddresses",MRA_DEF_FS_HIDE_MY_ADDRESSES));
			CHECK_DLG_BUTTON(hWndDlg,IDC_FILE_SEND_ADD_EXTRA_ADDRESS,DB_Mra_GetByte(NULL,"FileSendAddExtraAddresses",MRA_DEF_FS_ADD_EXTRA_ADDRESSES));
			if (DB_Mra_GetStaticStringW(NULL,"FileSendExtraAddresses",szBuff,SIZEOF(szBuff),NULL))
			{
				SET_DLG_ITEM_TEXT(hWndDlg,IDC_FILE_SEND_EXTRA_ADDRESS,szBuff);
			}

			CHECK_DLG_BUTTON(hWndDlg,IDC_FILE_SEND_ENABLE_MRIMPROXY_CONS,DB_Mra_GetByte(NULL,"FileSendEnableMRIMProxyCons",MRA_DEF_FS_ENABLE_MRIM_PROXY_CONS));
			
			SetDlgItemInt(hWndDlg,IDC_FILE_SEND_BLOCK_SIZE,DB_Mra_GetDword(NULL,"FileSendBlockSize",MRA_DEFAULT_FILE_SEND_BLOCK_SIZE),FALSE);

			MraFilesQueueDlgEnableDirectConsControls(hWndDlg,IS_DLG_BUTTON_CHECKED(hWndDlg,IDC_FILE_SEND_ENABLE_DIRECT_CONN));
		}
		return(TRUE);
	case WM_COMMAND:
		if (LOWORD(wParam)==IDC_FILE_SEND_ENABLE_DIRECT_CONN)
		{
			MraFilesQueueDlgEnableDirectConsControls(hWndDlg,IS_DLG_BUTTON_CHECKED(hWndDlg,IDC_FILE_SEND_ENABLE_DIRECT_CONN));
		}

		if (LOWORD(wParam)==IDC_FILE_SEND_ADD_EXTRA_ADDRESS)
		{
			EnableWindow(GetDlgItem(hWndDlg,IDC_FILE_SEND_EXTRA_ADDRESS),IS_DLG_BUTTON_CHECKED(hWndDlg,IDC_FILE_SEND_ADD_EXTRA_ADDRESS));
		}

		if ((LOWORD(wParam)==IDC_FILE_SEND_EXTRA_ADDRESS || LOWORD(wParam)==IDC_FILE_SEND_BLOCK_SIZE) && (HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus())) return(FALSE);
		SendMessage(GetParent(hWndDlg),PSM_CHANGED,0,0);
		break;
	case WM_NOTIFY:
		switch (((LPNMHDR)lParam)->code){
		case PSN_APPLY:
			{
				WCHAR szBuff[MAX_PATH];

				DB_Mra_SetByte(NULL,"FileSendEnableDirectConn",IS_DLG_BUTTON_CHECKED(hWndDlg,IDC_FILE_SEND_ENABLE_DIRECT_CONN));
				DB_Mra_SetByte(NULL,"FileSendNoOutConnOnRcv",IS_DLG_BUTTON_CHECKED(hWndDlg,IDC_FILE_SEND_NOOUTCONNECTIONONRECEIVE));
				DB_Mra_SetByte(NULL,"FileSendNoOutConnOnSend",IS_DLG_BUTTON_CHECKED(hWndDlg,IDC_FILE_SEND_NOOUTCONNECTIONONSEND));
				DB_Mra_SetByte(NULL,"FileSendIgnoryAdditionalPorts",IS_DLG_BUTTON_CHECKED(hWndDlg,IDC_FILE_SEND_IGNORYADDITIONALPORTS));
				DB_Mra_SetByte(NULL,"FileSendHideMyAddresses",IS_DLG_BUTTON_CHECKED(hWndDlg,IDC_FILE_SEND_HIDE_MY_ADDRESSES));
				DB_Mra_SetByte(NULL,"FileSendAddExtraAddresses",IS_DLG_BUTTON_CHECKED(hWndDlg,IDC_FILE_SEND_ADD_EXTRA_ADDRESS));
				GET_DLG_ITEM_TEXT(hWndDlg,IDC_FILE_SEND_EXTRA_ADDRESS,szBuff,SIZEOF(szBuff));
				DB_Mra_SetStringW(NULL,"FileSendExtraAddresses",szBuff);
				DB_Mra_SetDword(NULL,"FileSendBlockSize",(DWORD)GetDlgItemInt(hWndDlg,IDC_FILE_SEND_BLOCK_SIZE,NULL,FALSE));
				DB_Mra_SetByte(NULL,"FileSendEnableMRIMProxyCons",IS_DLG_BUTTON_CHECKED(hWndDlg,IDC_FILE_SEND_ENABLE_MRIMPROXY_CONS));
			}
			return(TRUE);
		}
		break;
	}
return(FALSE);
}



DWORD MraFilesQueueInitialize(DWORD dwSendTimeOutInterval,HANDLE *phFilesQueueHandle)
{
	DWORD dwRetErrorCode;

	if (phFilesQueueHandle)
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue;

		pmrafqFilesQueue=(MRA_FILES_QUEUE*)MEMALLOC(sizeof(MRA_FILES_QUEUE));
		if (pmrafqFilesQueue)
		{
			dwRetErrorCode=ListMTInitialize(&pmrafqFilesQueue->lmtListMT,0);
			if (dwRetErrorCode==NO_ERROR)
			{
				pmrafqFilesQueue->dwSendTimeOutInterval=dwSendTimeOutInterval;
				(*phFilesQueueHandle)=(HANDLE)pmrafqFilesQueue;
			}else{
				MEMFREE(pmrafqFilesQueue);
			}
		}else{
			dwRetErrorCode=GetLastError();
		}
	}else{
		dwRetErrorCode=ERROR_INVALID_HANDLE;
	}
return(dwRetErrorCode);
}


void MraFilesQueueDestroy(HANDLE hFilesQueueHandle)
{
	if (hFilesQueueHandle)
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem;

		ListMTLock(&pmrafqFilesQueue->lmtListMT);
		while(ListMTItemGetFirst(&pmrafqFilesQueue->lmtListMT,NULL,(LPVOID*)&pmrafqFilesQueueItem)==NO_ERROR)
		{
			MraFilesQueueItemFree(pmrafqFilesQueueItem);
		}
		ListMTUnLock(&pmrafqFilesQueue->lmtListMT);

		ListMTDestroy(&pmrafqFilesQueue->lmtListMT);
		MEMFREE(pmrafqFilesQueue);
	}
}


DWORD MraFilesQueueItemFindByID(HANDLE hFilesQueueHandle,DWORD dwIDRequest,MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem)
{
	DWORD dwRetErrorCode;

	if (hFilesQueueHandle)
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem;
		LIST_MT_ITERATOR lmtiIterator;

		dwRetErrorCode=ERROR_NOT_FOUND;
		ListMTLock(&pmrafqFilesQueue->lmtListMT);
		ListMTIteratorMoveFirst(&pmrafqFilesQueue->lmtListMT,&lmtiIterator);
		do
		{// ����
			if (ListMTIteratorGet(&lmtiIterator,NULL,(LPVOID*)&pmrafqFilesQueueItem)==NO_ERROR)
			if (pmrafqFilesQueueItem->dwIDRequest==dwIDRequest)
			{
				if (ppmrafqFilesQueueItem) (*ppmrafqFilesQueueItem)=pmrafqFilesQueueItem;
				dwRetErrorCode=NO_ERROR;
				break;
			}
		}while(ListMTIteratorMoveNext(&lmtiIterator));
		ListMTUnLock(&pmrafqFilesQueue->lmtListMT);
	}else{
		dwRetErrorCode=ERROR_INVALID_HANDLE;
	}
return(dwRetErrorCode);
}


HANDLE MraFilesQueueItemProxyByID(HANDLE hFilesQueueHandle,DWORD dwIDRequest)
{
	HANDLE hRet=NULL;
	MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem;

	if (MraFilesQueueItemFindByID(hFilesQueueHandle,dwIDRequest,&pmrafqFilesQueueItem)==NO_ERROR)
	{
		hRet=pmrafqFilesQueueItem->hMraMrimProxyData;
	}
return(hRet);
}


/*DWORD MraFilesQueueItemFindByEMail(HANDLE hFilesQueueHandle,LPSTR lpszEMail,SIZE_T dwEMailSize,MRA_FILES_QUEUE_ITEM **ppmrafqFilesQueueItem)
{
	DWORD dwRetErrorCode;

	if (hFilesQueueHandle)
	{
		CHAR szEMailLocal[MAX_EMAIL_LEN];
		SIZE_T dwEMailLocalSize;
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem;
		LIST_MT_ITERATOR lmtiIterator;

		dwRetErrorCode=ERROR_NOT_FOUND;
		ListMTLock(&pmrafqFilesQueue->lmtListMT);
		ListMTIteratorMoveFirst(&pmrafqFilesQueue->lmtListMT,&lmtiIterator);
		do
		{// ����
			if (ListMTIteratorGet(&lmtiIterator,NULL,(LPVOID*)&pmrafqFilesQueueItem)==NO_ERROR)
			if (DB_Mra_GetStaticStringA(pmrafqFilesQueueItem->hContact,"e-mail",szEMailLocal,SIZEOF(szEMailLocal),&dwEMailLocalSize))
			if (dwEMailSize==dwEMailLocalSize)
			if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,lpszEMail,dwEMailSize,szEMailLocal,dwEMailLocalSize)==CSTR_EQUAL)
			{
				if (ppmrafqFilesQueueItem) (*ppmrafqFilesQueueItem)=pmrafqFilesQueueItem;
				dwRetErrorCode=NO_ERROR;
				break;
			}
		}while(ListMTIteratorMoveNext(&lmtiIterator));
		ListMTUnLock(&pmrafqFilesQueue->lmtListMT);
	}else{
		dwRetErrorCode=ERROR_INVALID_HANDLE;
	}
return(dwRetErrorCode);
}*/


void MraFilesQueueItemFree(MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem)
{
 	LIST_MT *plmtListMT=(LIST_MT*)pmrafqFilesQueueItem->lmtListMTItem.lpListMT;

	for(SIZE_T i=0;i<pmrafqFilesQueueItem->dwFilesCount;i++)
	{
		MEMFREE(pmrafqFilesQueueItem->pmfqfFiles[i].lpwszName);
	}
	MEMFREE(pmrafqFilesQueueItem->pmfqfFiles);
	MEMFREE(pmrafqFilesQueueItem->pwszFilesList);
	MEMFREE(pmrafqFilesQueueItem->pwszDescription);
	MraAddrListFree(&pmrafqFilesQueueItem->malAddrList);
	MraMrimProxyFree(pmrafqFilesQueueItem->hMraMrimProxyData);
	MEMFREE(pmrafqFilesQueueItem->lpwszPath);
	ListMTLock(plmtListMT);
	ListMTItemDelete(plmtListMT,&pmrafqFilesQueueItem->lmtListMTItem);
	ListMTUnLock(plmtListMT);
	MEMFREE(pmrafqFilesQueueItem);
}





SIZE_T MraFilesQueueGetLocalAddressesList(LPSTR lpszBuff,SIZE_T dwBuffSize,DWORD dwPort)
{
	CHAR szHostName[MAX_PATH]={0};
	LPSTR lpszCurPos=lpszBuff;

	if (DB_Mra_GetByte(NULL,"FileSendHideMyAddresses",MRA_DEF_FS_HIDE_MY_ADDRESSES))
	{// �� ����� ����� ��� IP �����!!! :)
		if (DB_Mra_GetByte(NULL,"FileSendAddExtraAddresses",MRA_DEF_FS_ADD_EXTRA_ADDRESSES)==FALSE)
		{// ������ ���� �� ��������� ����� �������
			lpszCurPos+=mir_snprintf(lpszCurPos,(dwBuffSize-((SIZE_T)lpszCurPos-(SIZE_T)lpszBuff)),MRA_FILES_NULL_ADDRR);
		}
	}else{// ������ ������ ����� IP �������
		BYTE btAddress[32];
		DWORD dwSelfExternalIP;
		SIZE_T dwAdapter=0;
		hostent *sh;

		dwSelfExternalIP=NTOHL(DB_Mra_GetDword(NULL,"IP",0));
		if (dwSelfExternalIP)
		{
			memmove(&btAddress,&dwSelfExternalIP,sizeof(DWORD));
			lpszCurPos+=mir_snprintf(lpszCurPos,(dwBuffSize-((SIZE_T)lpszCurPos-(SIZE_T)lpszBuff)),"%lu.%lu.%lu.%lu:%lu;",btAddress[0],btAddress[1],btAddress[2],btAddress[3],dwPort);
		}

		if (gethostname(szHostName,SIZEOF(szHostName))==0)
		if ((sh=gethostbyname((LPSTR)&szHostName)))
		{
			while(sh->h_addr_list[dwAdapter])
			{
				lpszCurPos+=mir_snprintf(lpszCurPos,(dwBuffSize-((SIZE_T)lpszCurPos-(SIZE_T)lpszBuff)),"%s:%lu;",inet_ntoa(*((struct in_addr*)sh->h_addr_list[dwAdapter])),dwPort);
				dwAdapter++;
			}
		}
	}

	if (DB_Mra_GetByte(NULL,"FileSendAddExtraAddresses",MRA_DEF_FS_ADD_EXTRA_ADDRESSES))// ��������� ������������ �����
	if (DB_Mra_GetStaticStringA(NULL,"FileSendExtraAddresses",szHostName,SIZEOF(szHostName),NULL))
	{
		lpszCurPos+=mir_snprintf(lpszCurPos,(dwBuffSize-((SIZE_T)lpszCurPos-(SIZE_T)lpszBuff)),"%s:%lu;",szHostName,dwPort);
	}
return((lpszCurPos-lpszBuff));
}




DWORD MraFilesQueueAddReceive(HANDLE hFilesQueueHandle,DWORD dwFlags,HANDLE hContact,DWORD dwIDRequest,LPWSTR lpwszFiles,SIZE_T dwFilesSize,LPSTR lpszAddreses,SIZE_T dwAddresesSize)
{
	DWORD dwRetErrorCode;

	if (hFilesQueueHandle && dwIDRequest)
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem;

		pmrafqFilesQueueItem=(MRA_FILES_QUEUE_ITEM*)MEMALLOC(sizeof(MRA_FILES_QUEUE_ITEM)+sizeof(LPSTR)+64);
		if (pmrafqFilesQueueItem)
		{
			WCHAR szBuff[MAX_PATH];
			LPWSTR lpwszCurrentItem,lpwszDelimiter,lpwszEndItem;
			SIZE_T dwMemSize,dwAllocatedCount,dwFileNameTotalSize;
			CCSDATA ccs;
			PROTORECVFILET prf;

			//pmrafqFilesQueueItem->lmtListMTItem;
			pmrafqFilesQueueItem->bIsWorking=TRUE;
			pmrafqFilesQueueItem->dwSendTime=GetTickCount();
			pmrafqFilesQueueItem->dwIDRequest=dwIDRequest;
			pmrafqFilesQueueItem->dwFlags=dwFlags;
			pmrafqFilesQueueItem->hContact=hContact;
			if (DB_Mra_GetByte(NULL,"FileSendEnableMRIMProxyCons",MRA_DEF_FS_ENABLE_MRIM_PROXY_CONS)) pmrafqFilesQueueItem->hMraMrimProxyData=MraMrimProxyCreate();


			dwFileNameTotalSize=0;
			dwAllocatedCount=ALLOCATED_COUNT;
			pmrafqFilesQueueItem->dwFilesCount=0;
			pmrafqFilesQueueItem->dwFilesTotalSize=0;
			pmrafqFilesQueueItem->pmfqfFiles=(MRA_FILES_QUEUE_FILE*)MEMALLOC((sizeof(MRA_FILES_QUEUE_FILE)*dwAllocatedCount));
			lpwszCurrentItem=lpwszFiles;
			while(TRUE)
			{
				lpwszDelimiter=(LPWSTR)MemoryFind(((SIZE_T)lpwszCurrentItem-(SIZE_T)lpwszFiles),lpwszFiles,(dwFilesSize*sizeof(WCHAR)),";",2);
				if (lpwszDelimiter)
				{
					lpwszEndItem=(LPWSTR)MemoryFind((((SIZE_T)lpwszDelimiter+2)-(SIZE_T)lpwszFiles),lpwszFiles,(dwFilesSize*sizeof(WCHAR)),";",2);
					if (lpwszEndItem)
					{
						if (pmrafqFilesQueueItem->dwFilesCount==dwAllocatedCount)
						{
							dwAllocatedCount*=2;
							pmrafqFilesQueueItem->pmfqfFiles=(MRA_FILES_QUEUE_FILE*)MEMREALLOC(pmrafqFilesQueueItem->pmfqfFiles,(sizeof(MRA_FILES_QUEUE_FILE)*dwAllocatedCount));
						}

						dwMemSize=((SIZE_T)lpwszDelimiter-(SIZE_T)lpwszCurrentItem);
						pmrafqFilesQueueItem->pmfqfFiles[pmrafqFilesQueueItem->dwFilesCount].lpwszName=(LPWSTR)MEMALLOC(dwMemSize);
						memmove(pmrafqFilesQueueItem->pmfqfFiles[pmrafqFilesQueueItem->dwFilesCount].lpwszName,lpwszCurrentItem,dwMemSize);
						pmrafqFilesQueueItem->pmfqfFiles[pmrafqFilesQueueItem->dwFilesCount].dwSize=StrToUNum64((LPSTR)((SIZE_T)lpwszDelimiter+1),((SIZE_T)lpwszEndItem-((SIZE_T)lpwszDelimiter+1)));
						pmrafqFilesQueueItem->dwFilesTotalSize+=pmrafqFilesQueueItem->pmfqfFiles[pmrafqFilesQueueItem->dwFilesCount].dwSize;
						pmrafqFilesQueueItem->pmfqfFiles[pmrafqFilesQueueItem->dwFilesCount].dwNameLen=(dwMemSize/sizeof(WCHAR));
						dwFileNameTotalSize+=dwMemSize;
						
						pmrafqFilesQueueItem->dwFilesCount++;
						lpwszCurrentItem=(lpwszEndItem+1);
					}else{
						break;
					}
				}else{
					break;
				}
			}
			pmrafqFilesQueueItem->pmfqfFiles=(MRA_FILES_QUEUE_FILE*)MEMREALLOC(pmrafqFilesQueueItem->pmfqfFiles,(sizeof(MRA_FILES_QUEUE_FILE)*(pmrafqFilesQueueItem->dwFilesCount+4)));

			dwMemSize=(((pmrafqFilesQueueItem->dwFilesCount+4)*64)+(dwFileNameTotalSize*sizeof(WCHAR))+(dwAddresesSize*sizeof(WCHAR))+128);
			pmrafqFilesQueueItem->pwszFilesList=(LPWSTR)MEMALLOC(dwMemSize);
			pmrafqFilesQueueItem->pwszDescription=(LPWSTR)MEMALLOC(dwMemSize);


			lpwszDelimiter=pmrafqFilesQueueItem->pwszFilesList;
			lpwszCurrentItem=pmrafqFilesQueueItem->pwszDescription;
			StrFormatByteSizeW(pmrafqFilesQueueItem->dwFilesTotalSize,szBuff,SIZEOF(szBuff));
			lpwszCurrentItem+=mir_sntprintf(lpwszCurrentItem,((dwMemSize-((SIZE_T)lpwszCurrentItem-(SIZE_T)pmrafqFilesQueueItem->pwszDescription))/sizeof(WCHAR)),L"%I64u Files (%s)\r\n",pmrafqFilesQueueItem->dwFilesCount,szBuff);

			// description + filesnames
			for(SIZE_T i=0;i<pmrafqFilesQueueItem->dwFilesCount;i++)
			{
				lpwszDelimiter+=mir_sntprintf(lpwszDelimiter,((dwMemSize-((SIZE_T)lpwszDelimiter-(SIZE_T)pmrafqFilesQueueItem->pwszFilesList))/sizeof(WCHAR)),L"%s; ",pmrafqFilesQueueItem->pmfqfFiles[i].lpwszName);
				StrFormatByteSizeW(pmrafqFilesQueueItem->pmfqfFiles[i].dwSize,szBuff,SIZEOF(szBuff));
				lpwszCurrentItem+=mir_sntprintf(lpwszCurrentItem,((dwMemSize-((SIZE_T)lpwszCurrentItem-(SIZE_T)pmrafqFilesQueueItem->pwszDescription))/sizeof(WCHAR)),L"%s - %s\r\n",pmrafqFilesQueueItem->pmfqfFiles[i].lpwszName,szBuff);
			}

			lpwszCurrentItem+=MultiByteToWideChar(MRA_CODE_PAGE,0,lpszAddreses,dwAddresesSize,lpwszCurrentItem,((dwMemSize-((SIZE_T)lpwszCurrentItem-(SIZE_T)pmrafqFilesQueueItem->pwszDescription))/sizeof(WCHAR)));
			(*lpwszCurrentItem)=0;
			//lpwszCurrentItem++;


			MraAddrListGetFromBuff(lpszAddreses,dwAddresesSize,&pmrafqFilesQueueItem->malAddrList);
			MraAddrListStoreToContact(pmrafqFilesQueueItem->hContact,&pmrafqFilesQueueItem->malAddrList);

			ListMTLock(&pmrafqFilesQueue->lmtListMT);
			ListMTItemAdd(&pmrafqFilesQueue->lmtListMT,&pmrafqFilesQueueItem->lmtListMTItem,pmrafqFilesQueueItem);
			ListMTUnLock(&pmrafqFilesQueue->lmtListMT);


			// Send chain event

			ccs.szProtoService=PSR_FILE;
			ccs.hContact=hContact;
			ccs.wParam=0;
			ccs.lParam=(LPARAM)&prf;
			prf.flags=PREF_UNICODE;
			prf.timestamp=_time32(NULL);
			prf.tszDescription=pmrafqFilesQueueItem->pwszDescription;
			prf.fileCount=1;//pmrafqFilesQueueItem->dwFilesCount;
			prf.ptszFiles=&pmrafqFilesQueueItem->pwszFilesList;
			prf.lParam=dwIDRequest;
 
			CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs);

			dwRetErrorCode=NO_ERROR;
		}else{
			dwRetErrorCode=GetLastError();
		}
	}else{
		dwRetErrorCode=ERROR_INVALID_HANDLE;
	}
return(dwRetErrorCode);
}



DWORD MraFilesQueueAddSend(HANDLE hFilesQueueHandle,DWORD dwFlags,HANDLE hContact,LPWSTR *plpwszFiles,SIZE_T dwFilesCount,DWORD *pdwIDRequest)
{
	DWORD dwRetErrorCode;

	if (hFilesQueueHandle)
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem;


		pmrafqFilesQueueItem=(MRA_FILES_QUEUE_ITEM*)MEMALLOC(sizeof(MRA_FILES_QUEUE_ITEM)+sizeof(LPSTR)+64);
		if (pmrafqFilesQueueItem)
		{
			SIZE_T i;
			ULARGE_INTEGER uliFileSize;
			WIN32_FILE_ATTRIBUTE_DATA wfad;

			//pmrafqFilesQueueItem->lmtListMTItem;
			pmrafqFilesQueueItem->bIsWorking=TRUE;
			pmrafqFilesQueueItem->dwSendTime=GetTickCount();
			pmrafqFilesQueueItem->dwIDRequest=InterlockedIncrement((LONG volatile*)&masMraSettings.dwCMDNum);// ����������, ��������� �������������
			pmrafqFilesQueueItem->dwFlags=dwFlags;
			pmrafqFilesQueueItem->hContact=hContact;
			if (DB_Mra_GetByte(NULL,"FileSendEnableMRIMProxyCons",MRA_DEF_FS_ENABLE_MRIM_PROXY_CONS)) pmrafqFilesQueueItem->hMraMrimProxyData=MraMrimProxyCreate();
			pmrafqFilesQueueItem->dwFilesCount=dwFilesCount;
			pmrafqFilesQueueItem->pmfqfFiles=(MRA_FILES_QUEUE_FILE*)MEMALLOC((sizeof(MRA_FILES_QUEUE_FILE)*(pmrafqFilesQueueItem->dwFilesCount+1)));
			pmrafqFilesQueueItem->dwFilesTotalSize=0;

			for(i=0;i<pmrafqFilesQueueItem->dwFilesCount;i++)
			{
				if (GetFileAttributesExW(plpwszFiles[i],GetFileExInfoStandard,&wfad))
				{
					uliFileSize.LowPart=wfad.nFileSizeLow;
					uliFileSize.HighPart=wfad.nFileSizeHigh;
					pmrafqFilesQueueItem->pmfqfFiles[i].dwSize=uliFileSize.QuadPart;
					pmrafqFilesQueueItem->dwFilesTotalSize+=uliFileSize.QuadPart;
				}else{
					pmrafqFilesQueueItem->pmfqfFiles[i].dwSize=0;
				}
				pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen=lstrlenW(plpwszFiles[i]);
				pmrafqFilesQueueItem->pmfqfFiles[i].lpwszName=(LPWSTR)MEMALLOC((pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen*sizeof(WCHAR)));
				if (pmrafqFilesQueueItem->pmfqfFiles[i].lpwszName)
				{
					memmove(pmrafqFilesQueueItem->pmfqfFiles[i].lpwszName,plpwszFiles[i],(pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen*sizeof(WCHAR)));
				}
			}
			//pmrafqFilesQueueItem->malAddrList.dwAddrCount=0;
			//pmrafqFilesQueueItem->pmfqaAddreses=NULL;
			pmrafqFilesQueueItem->bSending=TRUE;
			if (pdwIDRequest) (*pdwIDRequest)=pmrafqFilesQueueItem->dwIDRequest;

			ListMTLock(&pmrafqFilesQueue->lmtListMT);
			ListMTItemAdd(&pmrafqFilesQueue->lmtListMT,&pmrafqFilesQueueItem->lmtListMTItem,pmrafqFilesQueueItem);
			ListMTUnLock(&pmrafqFilesQueue->lmtListMT);

			{
				MRA_FILES_THREADPROC_PARAMS *pmftpp=(MRA_FILES_THREADPROC_PARAMS*)MEMALLOC(sizeof(MRA_FILES_THREADPROC_PARAMS));
				pmftpp->hFilesQueueHandle=hFilesQueueHandle;
				pmftpp->pmrafqFilesQueueItem=pmrafqFilesQueueItem;
				
				pmrafqFilesQueueItem->hThread=(HANDLE)mir_forkthread((pThreadFunc)MraFilesQueueSendThreadProc,pmftpp);
			}

			dwRetErrorCode=NO_ERROR;
		}else{
			dwRetErrorCode=GetLastError();
		}
	}else{
		dwRetErrorCode=ERROR_INVALID_HANDLE;
	}
return(dwRetErrorCode);
}



DWORD MraFilesQueueAccept(HANDLE hFilesQueueHandle,DWORD dwIDRequest,LPWSTR lpwszPath,SIZE_T dwPathSize)
{
	DWORD dwRetErrorCode;

	if (hFilesQueueHandle && lpwszPath && dwPathSize)
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem;

		ListMTLock(&pmrafqFilesQueue->lmtListMT);
		if ((dwRetErrorCode=MraFilesQueueItemFindByID(hFilesQueueHandle,dwIDRequest,&pmrafqFilesQueueItem))==NO_ERROR)
		{
			MRA_FILES_THREADPROC_PARAMS *pmftpp=(MRA_FILES_THREADPROC_PARAMS*)MEMALLOC(sizeof(MRA_FILES_THREADPROC_PARAMS));
			pmrafqFilesQueueItem->lpwszPath=(LPWSTR)MEMALLOC((dwPathSize*sizeof(WCHAR)));
			pmrafqFilesQueueItem->dwPathSize=dwPathSize;
			memmove(pmrafqFilesQueueItem->lpwszPath,lpwszPath,(dwPathSize*sizeof(WCHAR)));

			if ( (*(WCHAR*)(pmrafqFilesQueueItem->lpwszPath+(pmrafqFilesQueueItem->dwPathSize-1)))!='\\')
			{// add slash at the end if needed
				(*(WCHAR*)(pmrafqFilesQueueItem->lpwszPath+pmrafqFilesQueueItem->dwPathSize))='\\';
				pmrafqFilesQueueItem->dwPathSize++;
				(*(WCHAR*)(pmrafqFilesQueueItem->lpwszPath+pmrafqFilesQueueItem->dwPathSize))=0;
			}

			pmftpp->hFilesQueueHandle=hFilesQueueHandle;
			pmftpp->pmrafqFilesQueueItem=pmrafqFilesQueueItem;
			
			pmrafqFilesQueueItem->hThread=(HANDLE)mir_forkthread((pThreadFunc)MraFilesQueueRecvThreadProc,pmftpp);
		}
		ListMTUnLock(&pmrafqFilesQueue->lmtListMT);
	}else{
		dwRetErrorCode=ERROR_INVALID_HANDLE;
	}
return(dwRetErrorCode);
}


DWORD MraFilesQueueCancel(HANDLE hFilesQueueHandle,DWORD dwIDRequest,BOOL bSendDecline)
{
	DWORD dwRetErrorCode;

	if (hFilesQueueHandle)
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem;

		ListMTLock(&pmrafqFilesQueue->lmtListMT);
		if ((dwRetErrorCode=MraFilesQueueItemFindByID(hFilesQueueHandle,dwIDRequest,&pmrafqFilesQueueItem))==NO_ERROR)
		{//***deb closesocket, send message to thread
			InterlockedExchange((volatile LONG*)&pmrafqFilesQueueItem->bIsWorking,FALSE);

			if (bSendDecline)
			{
				CHAR szEMail[MAX_EMAIL_LEN];
				SIZE_T dwEMailSize;

				if (DB_Mra_GetStaticStringA(pmrafqFilesQueueItem->hContact,"e-mail",szEMail,SIZEOF(szEMail),&dwEMailSize))
				{
					MraSendCommand_FileTransferAck(FILE_TRANSFER_STATUS_DECLINE,szEMail,dwEMailSize,dwIDRequest,NULL,0);
				}
			}
			
			MraMrimProxyCloseConnection(pmrafqFilesQueueItem->hMraMrimProxyData);

			Netlib_CloseHandle(pmrafqFilesQueueItem->hListen);
			pmrafqFilesQueueItem->hListen=NULL;

			Netlib_CloseHandle(pmrafqFilesQueueItem->hConnection);
			pmrafqFilesQueueItem->hConnection=NULL;

			SetEvent(pmrafqFilesQueueItem->hWaitHandle);

			if (pmrafqFilesQueueItem->hThread==NULL)
			{
				MraFilesQueueItemFree(pmrafqFilesQueueItem);
			}
		}
		ListMTUnLock(&pmrafqFilesQueue->lmtListMT);
	}else{
		dwRetErrorCode=ERROR_INVALID_HANDLE;
	}
return(dwRetErrorCode);
}


DWORD MraFilesQueueStartMrimProxy(HANDLE hFilesQueueHandle,DWORD dwIDRequest)
{
	DWORD dwRetErrorCode;

	if (hFilesQueueHandle && DB_Mra_GetByte(NULL,"FileSendEnableMRIMProxyCons",MRA_DEF_FS_ENABLE_MRIM_PROXY_CONS))
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem;

		ListMTLock(&pmrafqFilesQueue->lmtListMT);
		if ((dwRetErrorCode=MraFilesQueueItemFindByID(hFilesQueueHandle,dwIDRequest,&pmrafqFilesQueueItem))==NO_ERROR)
		{//***deb
			if (pmrafqFilesQueueItem->bSending==FALSE)
			{// receiving
				SetEvent(pmrafqFilesQueueItem->hWaitHandle);// cancel wait incomming connection
			}else{// sending

			}
		}
		ListMTUnLock(&pmrafqFilesQueue->lmtListMT);
	}else{
		dwRetErrorCode=ERROR_INVALID_HANDLE;
	}
return(dwRetErrorCode);
}


DWORD MraFilesQueueFree(HANDLE hFilesQueueHandle,DWORD dwIDRequest)
{
	DWORD dwRetErrorCode;

	if (hFilesQueueHandle)
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem;
		LIST_MT_ITERATOR lmtiIterator;

		dwRetErrorCode=ERROR_NOT_FOUND;
		ListMTLock(&pmrafqFilesQueue->lmtListMT);
		ListMTIteratorMoveFirst(&pmrafqFilesQueue->lmtListMT,&lmtiIterator);
		do
		{// ����
			if (ListMTIteratorGet(&lmtiIterator,NULL,(LPVOID*)&pmrafqFilesQueueItem)==NO_ERROR)
			if (pmrafqFilesQueueItem->dwIDRequest==dwIDRequest)
			{
				MraFilesQueueItemFree(pmrafqFilesQueueItem);
				dwRetErrorCode=NO_ERROR;
				break;
			}
		}while(ListMTIteratorMoveNext(&lmtiIterator));
		ListMTUnLock(&pmrafqFilesQueue->lmtListMT);
	}else{
		dwRetErrorCode=ERROR_INVALID_HANDLE;
	}
return(dwRetErrorCode);
}


DWORD MraFilesQueueSendMirror(HANDLE hFilesQueueHandle,DWORD dwIDRequest,LPSTR lpszAddreses,SIZE_T dwAddresesSize)
{
	DWORD dwRetErrorCode;

	if (hFilesQueueHandle)
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem;

		ListMTLock(&pmrafqFilesQueue->lmtListMT);
		if ((dwRetErrorCode=MraFilesQueueItemFindByID(hFilesQueueHandle,dwIDRequest,&pmrafqFilesQueueItem))==NO_ERROR)
		{//
			MraAddrListGetFromBuff(lpszAddreses,dwAddresesSize,&pmrafqFilesQueueItem->malAddrList);
			MraAddrListStoreToContact(pmrafqFilesQueueItem->hContact,&pmrafqFilesQueueItem->malAddrList);

			pmrafqFilesQueueItem->hConnection=NULL;
			SetEvent(pmrafqFilesQueueItem->hWaitHandle);
		}
		ListMTUnLock(&pmrafqFilesQueue->lmtListMT);
	}else{
		dwRetErrorCode=ERROR_INVALID_HANDLE;
	}
return(dwRetErrorCode);
}



BOOL MraFilesQueueHandCheck(HANDLE hConnection,MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem)
{
	BOOL bRet=FALSE;

	if (hConnection && pmrafqFilesQueueItem)
	{
		CHAR szEMail[MAX_EMAIL_LEN]={0},szEMailMy[MAX_EMAIL_LEN]={0};
		BYTE btBuff[((MAX_EMAIL_LEN*2)+(sizeof(MRA_FT_HELLO)*2)+8)]={0};
		SIZE_T dwEMailSize,dwEMailMySize,dwBuffSize;

		DB_Mra_GetStaticStringA(NULL,"e-mail",szEMailMy,SIZEOF(szEMailMy),&dwEMailMySize);BuffToLowerCase(szEMailMy,szEMailMy,dwEMailMySize);
		DB_Mra_GetStaticStringA(pmrafqFilesQueueItem->hContact,"e-mail",szEMail,SIZEOF(szEMail),&dwEMailSize);BuffToLowerCase(szEMail,szEMail,dwEMailSize);

		if (pmrafqFilesQueueItem->bSending==FALSE)
		{// receiving
			dwBuffSize=(mir_snprintf((LPSTR)btBuff,SIZEOF(btBuff),"%s %s",MRA_FT_HELLO,szEMailMy)+1);
			if (dwBuffSize==Netlib_Send(hConnection,(LPSTR)btBuff,dwBuffSize,0))
			{// my email sended
				ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_INITIALISING,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
				dwBuffSize=Netlib_Recv(hConnection,(LPSTR)btBuff,sizeof(btBuff),0);
				if ((dwEMailSize+sizeof(MRA_FT_HELLO)+1)==dwBuffSize)
				{// email received
					mir_snprintf(((LPSTR)btBuff+dwBuffSize),(SIZEOF(btBuff)-dwBuffSize),"%s %s",MRA_FT_HELLO,szEMail);
					if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,(LPSTR)btBuff,dwBuffSize,((LPSTR)btBuff+dwBuffSize),dwBuffSize)==CSTR_EQUAL)
					{// email verifyed
						bRet=TRUE;
					}
				}
			}
		}else{// sending
			dwBuffSize=Netlib_Recv(hConnection,(LPSTR)btBuff,sizeof(btBuff),0);
			if ((dwEMailSize+sizeof(MRA_FT_HELLO)+1)==dwBuffSize)
			{// email received
				ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_INITIALISING,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
				mir_snprintf(((LPSTR)btBuff+dwBuffSize),(SIZEOF(btBuff)-dwBuffSize),"%s %s",MRA_FT_HELLO,szEMail);
				if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,(LPSTR)btBuff,dwBuffSize,((LPSTR)btBuff+dwBuffSize),dwBuffSize)==CSTR_EQUAL)
				{// email verifyed
					dwBuffSize=(mir_snprintf((LPSTR)btBuff,SIZEOF(btBuff),"%s %s",MRA_FT_HELLO,szEMailMy)+1);
					if (dwBuffSize==Netlib_Send(hConnection,(LPSTR)btBuff,dwBuffSize,0))
					{// my email sended
						bRet=TRUE;
					}
				}
			}
		}
	}
return(bRet);
}


HANDLE MraFilesQueueConnectOut(MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem)
{
	HANDLE hRet;

	if (pmrafqFilesQueueItem)
	{
		if (DB_Mra_GetByte(NULL,"FileSendEnableDirectConn",MRA_DEF_FS_ENABLE_DIRECT_CONN) && InterlockedExchangeAdd((volatile LONG*)&pmrafqFilesQueueItem->bIsWorking,0) && ((pmrafqFilesQueueItem->bSending==FALSE && DB_Mra_GetByte(NULL,"FileSendNoOutConnOnRcv",MRA_DEF_FS_NO_OUT_CONN_ON_RCV)==FALSE) || (pmrafqFilesQueueItem->bSending==TRUE && DB_Mra_GetByte(NULL,"FileSendNoOutConnOnSend",MRA_DEF_FS_NO_OUT_CONN_ON_SEND)==FALSE)))
		{
			BOOL bFiltering=FALSE,bIsHTTPSProxyUsed=IsHTTPSProxyUsed(masMraSettings.hNetlibUser);
			DWORD dwLocalPort,dwConnectReTryCount,dwCurConnectReTryCount;
			SIZE_T i,dwAddrCount;
			NETLIBOPENCONNECTION nloc={0};

			dwLocalPort=0;

			if (DB_Mra_GetByte(NULL,"FileSendIgnoryAdditionalPorts",MRA_DEF_FS_IGNORY_ADDITIONAL_PORTS) || bIsHTTPSProxyUsed)
			{// ��������� ����� ��� ������ IP, ������ 3 ����� ����������� ������ � ������
				if (bIsHTTPSProxyUsed)
				{// ����� https ������ ������ 443 ����
					dwLocalPort=MRA_SERVER_PORT_HTTPS;
				}else{
					if ((dwLocalPort=DB_Mra_GetWord(NULL,"ServerPort",MRA_DEFAULT_SERVER_PORT))==MRA_SERVER_PORT_STANDART_NLB) dwLocalPort=MRA_SERVER_PORT_STANDART;
				}

				dwAddrCount=0;
				for(i=0;i<pmrafqFilesQueueItem->malAddrList.dwAddrCount;i++)
				{
					if (dwLocalPort==pmrafqFilesQueueItem->malAddrList.pmaliAddress[i].dwPort)
					{
						bFiltering=TRUE;
						dwAddrCount++;
					}
				}
			}
			if (bFiltering==FALSE) dwAddrCount=pmrafqFilesQueueItem->malAddrList.dwAddrCount;

			if (dwAddrCount)
			{
				pmrafqFilesQueueItem->hConnection=NULL;
				dwConnectReTryCount=DB_Mra_GetDword(NULL,"ConnectReTryCountFileSend",MRA_DEFAULT_CONN_RETRY_COUNT_FILES);
				nloc.cbSize=sizeof(nloc);
				nloc.flags=NLOCF_V2;
				nloc.timeout=DB_Mra_GetDword(NULL,"TimeOutConnectFileSend",((MRA_TIMEOUT_DIRECT_CONN-1)/(dwAddrCount*dwConnectReTryCount)));// -1 ��� ����� ��� �����
				if (nloc.timeout<MRA_TIMEOUT_CONN_MIN) nloc.timeout=MRA_TIMEOUT_CONN_MIN;
				if (nloc.timeout>MRA_TIMEOUT_CONN_���) nloc.timeout=MRA_TIMEOUT_CONN_���;

				for(i=0;i<pmrafqFilesQueueItem->malAddrList.dwAddrCount;i++)
				{// Set up the sockaddr structure
					if (dwLocalPort==pmrafqFilesQueueItem->malAddrList.pmaliAddress[i].dwPort || bFiltering==FALSE)
					{
						ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTING,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);

						nloc.szHost=inet_ntoa((*((in_addr*)&pmrafqFilesQueueItem->malAddrList.pmaliAddress[i].dwAddr)));
						nloc.wPort=(WORD)pmrafqFilesQueueItem->malAddrList.pmaliAddress[i].dwPort;

						dwCurConnectReTryCount=dwConnectReTryCount;
						do{
							pmrafqFilesQueueItem->hConnection=(HANDLE)CallService(MS_NETLIB_OPENCONNECTION,(WPARAM)masMraSettings.hNetlibUser,(LPARAM)&nloc);
						}while(--dwCurConnectReTryCount && pmrafqFilesQueueItem->hConnection==NULL);

						if (pmrafqFilesQueueItem->hConnection)
						{
							ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
							if (MraFilesQueueHandCheck(pmrafqFilesQueueItem->hConnection,pmrafqFilesQueueItem))
							{// ����� ������������� � ��� ��� �����
								DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"OldIP",DB_Mra_GetDword(pmrafqFilesQueueItem->hContact,"IP",0));
								DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"IP",HTONL(pmrafqFilesQueueItem->malAddrList.pmaliAddress[i].dwAddr));
								break;
							}else{// ������� �� ���� ������������ :)
								Netlib_CloseHandle(pmrafqFilesQueueItem->hConnection);
								pmrafqFilesQueueItem->hConnection=NULL;
							}
						}
					}
				}
			}
		}
		hRet=pmrafqFilesQueueItem->hConnection;
	}else{
		hRet=NULL;
	}
return(hRet);
}


LPWSTR GetFileNameFromFullPathW(LPWSTR lpwszFullPath,SIZE_T dwFullPathSize)
{
	LPWSTR lpwszFileName=lpwszFullPath,lpwszCurPos;

	lpwszCurPos=(lpwszFullPath+dwFullPathSize);
	for (;lpwszCurPos>lpwszFullPath;lpwszCurPos--)
	{
		if ((*lpwszCurPos)=='\\')
		{
			lpwszFileName=(lpwszCurPos+1);
			break;
		}
	}
return(lpwszFileName);
}



HANDLE MraFilesQueueConnectIn(MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem)
{
	HANDLE hRet=NULL;

	if (pmrafqFilesQueueItem)
	if (InterlockedExchangeAdd((volatile LONG*)&pmrafqFilesQueueItem->bIsWorking,0))
	{
		CHAR szEMail[MAX_EMAIL_LEN];
		SIZE_T dwEMailSize;

		if (DB_Mra_GetStaticStringA(pmrafqFilesQueueItem->hContact,"e-mail",szEMail,SIZEOF(szEMail),&dwEMailSize))
		{
			CHAR szAddrList[2048]={0};
			SIZE_T dwAddrListSize;

			if (DB_Mra_GetByte(NULL,"FileSendEnableDirectConn",MRA_DEF_FS_ENABLE_DIRECT_CONN))
			{// �������� ������ � ������������ � ��������� � �������� ������� ����
				NETLIBBIND nlbBind={0};

				nlbBind.cbSize=sizeof(nlbBind);
				nlbBind.pfnNewConnectionV2=MraFilesQueueConnectionReceived;
				nlbBind.wPort=0;
				nlbBind.pExtra=(LPVOID)pmrafqFilesQueueItem;

				pmrafqFilesQueueItem->hListen=(HANDLE)CallService(MS_NETLIB_BINDPORT,(WPARAM)masMraSettings.hNetlibUser,(LPARAM)&nlbBind);
				if (pmrafqFilesQueueItem->hListen)
				{
					ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_LISTENING,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
					dwAddrListSize=MraFilesQueueGetLocalAddressesList(szAddrList,sizeof(szAddrList),nlbBind.wPort);
				}else{// �� ������ ������� ����, �� ������.
					ShowFormatedErrorMessage(L"Files exchange: cant create listen soscket, will try connect to remonte host. Error",GetLastError());
					
					//dwAddrListSize=0;
					memmove(szAddrList,MRA_FILES_NULL_ADDRR,sizeof(MRA_FILES_NULL_ADDRR));
					dwAddrListSize=(sizeof(MRA_FILES_NULL_ADDRR)-1);
				}
			}else{// ����������� ������ �����, ����� ����� �� ������������ � �� ������� ����
				memmove(szAddrList,MRA_FILES_NULL_ADDRR,sizeof(MRA_FILES_NULL_ADDRR));
				dwAddrListSize=(sizeof(MRA_FILES_NULL_ADDRR)-1);
			}

			if (dwAddrListSize)
			{
				pmrafqFilesQueueItem->hWaitHandle=CreateEvent(NULL,TRUE,FALSE,NULL);
				if (pmrafqFilesQueueItem->bSending==FALSE)
				{// ����������� ���������� ����������, �� ���� ����������� �� ������
					MraSendCommand_FileTransferAck(FILE_TRANSFER_MIRROR,szEMail,dwEMailSize,pmrafqFilesQueueItem->dwIDRequest,(LPBYTE)szAddrList,dwAddrListSize);
				}else{// ����� ���������� ������ �� ��������(������������ ����������)
					// ������ ��������� ������ ������ ��� �������� ������ �������
					LPWSTR lpwszFiles,lpwszCurPos;
					SIZE_T dwFilesSize;

					dwFilesSize=((MAX_PATH*2)*pmrafqFilesQueueItem->dwFilesCount);
					lpwszFiles=(LPWSTR)MEMALLOC((dwFilesSize*sizeof(WCHAR)));
					if (lpwszFiles)
					{
						lpwszCurPos=lpwszFiles;
						for(SIZE_T i=0;i<pmrafqFilesQueueItem->dwFilesCount;i++)
						{
							lpwszCurPos+=mir_sntprintf(lpwszCurPos,(dwFilesSize-((SIZE_T)lpwszCurPos-(SIZE_T)lpwszFiles)),L"%s;%I64u;",GetFileNameFromFullPathW(pmrafqFilesQueueItem->pmfqfFiles[i].lpwszName,pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen),pmrafqFilesQueueItem->pmfqfFiles[i].dwSize);
						}
						dwFilesSize=(lpwszCurPos-lpwszFiles);// size in WCHARs

						if (pmrafqFilesQueueItem->hMraMrimProxyData)
						{// ������������� ������ ��� ���������� ������, ���� ��� ���������
							LPSTR lpszFiles;
							SIZE_T dwFilesSizeA;

							dwFilesSizeA=WideCharToMultiByte(MRA_CODE_PAGE,0,lpwszFiles,dwFilesSize,NULL,0,NULL,NULL);
							lpszFiles=(LPSTR)MEMALLOC((dwFilesSizeA+MAX_PATH));
							if (lpszFiles)
							{
								dwFilesSizeA=WideCharToMultiByte(MRA_CODE_PAGE,0,lpwszFiles,dwFilesSize,lpszFiles,(dwFilesSizeA+MAX_PATH),NULL,NULL);
								MraMrimProxySetData(pmrafqFilesQueueItem->hMraMrimProxyData,szEMail,dwEMailSize,pmrafqFilesQueueItem->dwIDRequest,MRIM_PROXY_TYPE_FILES,lpszFiles,dwFilesSizeA,NULL,0,NULL);
								MEMFREE(lpszFiles);
							}
							//MraMrimProxySetData(pmrafqFilesQueueItem->hMraMrimProxyData,szEMail,dwEMailSize,pmrafqFilesQueueItem->dwIDRequest,MRIM_PROXY_TYPE_FILES,(LPSTR)lpwszFiles,dwFilesSize,NULL,0,NULL);
						}
						MraSendCommand_FileTransfer(szEMail,dwEMailSize,pmrafqFilesQueueItem->dwIDRequest,pmrafqFilesQueueItem->dwFilesTotalSize,lpwszFiles,dwFilesSize,szAddrList,dwAddrListSize);
						
						MEMFREE(lpwszFiles);
					}
				}
				WaitForSingleObjectEx(pmrafqFilesQueueItem->hWaitHandle,INFINITE,FALSE);
				CloseHandle(pmrafqFilesQueueItem->hWaitHandle);
				pmrafqFilesQueueItem->hWaitHandle=NULL;
			}
		}
		hRet=pmrafqFilesQueueItem->hConnection;
	}
return(hRet);
}

// This function is called from the Netlib when someone is connecting to
// one of our incomming DC ports
void MraFilesQueueConnectionReceived(HANDLE hNewConnection,DWORD dwRemoteIP,void *pExtra)
{
	if (pExtra)
	{
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem=(MRA_FILES_QUEUE_ITEM*)pExtra;

		ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
		if (MraFilesQueueHandCheck(hNewConnection,pmrafqFilesQueueItem))
		{// ����� ������������� � ��� ��� �����
			pmrafqFilesQueueItem->hConnection=hNewConnection;
			ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
			DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"OldIP",DB_Mra_GetDword(pmrafqFilesQueueItem->hContact,"IP",0));
			DB_Mra_SetDword(pmrafqFilesQueueItem->hContact,"IP",dwRemoteIP);
			SetEvent(pmrafqFilesQueueItem->hWaitHandle);
		}else{// ������� ��� �� �� ���� ������������ :)
			ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_LISTENING,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
			Netlib_CloseHandle(hNewConnection);
		}
	}else{
		Netlib_CloseHandle(hNewConnection);
		MraPopupShowFromAgentW(MRA_POPUP_TYPE_DEBUG,0,TranslateW(L"MraFilesQueueConnectionReceived: connection accepted, but pExtra=NULL, this is miranda bug."));
		DebugBreak();
	}
}



void MraFilesQueueRecvThreadProc(LPVOID lpParameter)
{
	DWORD dwRetErrorCode=NO_ERROR;

	if (lpParameter)
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem=((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->pmrafqFilesQueueItem;
	    
		WCHAR wszFileName[MAX_FILEPATH]={0};
		WCHAR szErrorText[2048];
		BYTE btBuff[BUFF_SIZE_RCV];
		BOOL bContinue,bFailed,bOK,bConnected;
		DWORD dwReceived,dwUpdateTimeNext,dwUpdateTimeCur;
		HANDLE hFile;
		SIZE_T i,dwBuffSizeUsed;
		LARGE_INTEGER liFileSize;
		NETLIBSELECT nls={0};
		PROTOFILETRANSFERSTATUS pfts={0};

		MEMFREE(lpParameter);

		bFailed=TRUE;
		bConnected=FALSE;
		nls.cbSize=sizeof(nls);
		pfts.cbSize=sizeof(pfts);
		pfts.hContact=pmrafqFilesQueueItem->hContact;
		pfts.flags=(PFTS_RECEIVING|PFTS_UNICODE);//		pfts.sending=pmrafqFilesQueueItem->bSending;	//true if sending, false if receiving
		//pfts.files;
		pfts.totalFiles=pmrafqFilesQueueItem->dwFilesCount;
		//pfts.currentFileNumber=0;
		pfts.totalBytes=pmrafqFilesQueueItem->dwFilesTotalSize;
		//pfts.totalProgress=0;
		pfts.wszWorkingDir=pmrafqFilesQueueItem->lpwszPath;
		//pfts.currentFile;
		//pfts.currentFileSize;
		//pfts.currentFileProgress;
		//pfts.currentFileTime;  //as seconds since 1970

		if (MraFilesQueueConnectOut(pmrafqFilesQueueItem))
		{
			bConnected=TRUE;
		}else{
			if (MraFilesQueueConnectIn(pmrafqFilesQueueItem))
			{
				bConnected=TRUE;
			}else{
				if (InterlockedExchangeAdd((volatile LONG*)&pmrafqFilesQueueItem->bIsWorking,0))
				{
					ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKRESULT_CONNECTPROXY,ACKRESULT_CONNECTED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
					if (MraMrimProxyConnect(pmrafqFilesQueueItem->hMraMrimProxyData,&pmrafqFilesQueueItem->hConnection)==NO_ERROR)
					{// ������������ � ������, ��������� �� �� ������ (��� ���, �� ���� ��� ����)
						if (MraFilesQueueHandCheck(pmrafqFilesQueueItem->hConnection,pmrafqFilesQueueItem))
						{// ����� ������������� � ��� ��� �����// pmrafqFilesQueueItem->bSending
							ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
							bConnected=TRUE;
						}
					}
				}
			}
		}

		if (bConnected)
		{// email verifyed
			bFailed=FALSE;
			for(i=0;i<pmrafqFilesQueueItem->dwFilesCount;i++)
			{// receiving files
				pfts.currentFileNumber=i;
				pfts.wszCurrentFile=wszFileName;
				pfts.currentFileSize=pmrafqFilesQueueItem->pmfqfFiles[i].dwSize;
				pfts.currentFileProgress=0;
				//pfts.currentFileTime;  //as seconds since 1970
				
				if ((pmrafqFilesQueueItem->dwPathSize+pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen)<SIZEOF(wszFileName))
				{
					memmove(wszFileName,pmrafqFilesQueueItem->lpwszPath,(pmrafqFilesQueueItem->dwPathSize*sizeof(WCHAR)));
					memmove((wszFileName+pmrafqFilesQueueItem->dwPathSize),pmrafqFilesQueueItem->pmfqfFiles[i].lpwszName,((pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen+1)*sizeof(WCHAR)));
					wszFileName[pmrafqFilesQueueItem->dwPathSize+pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen]=0;
				}else{
					dwRetErrorCode=ERROR_BAD_PATHNAME;
					ShowFormatedErrorMessage(L"Receive files: error",dwRetErrorCode);
					bFailed=TRUE;
					break;
				}

				//***deb add
				//dwBuffSizeUsed=ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_FILERESUME,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,(LPARAM)&pfts);

				ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_NEXTFILE,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
				
				//dwBuffSizeUsed=(mir_snprintf((LPSTR)btBuff,SIZEOF(btBuff),"%s %S",MRA_FT_GET_FILE,pmrafqFilesQueueItem->pmfqfFiles[i].lpwszName)+1);
				memmove(btBuff,MRA_FT_GET_FILE,sizeof(MRA_FT_GET_FILE));
				btBuff[(sizeof(MRA_FT_GET_FILE)-1)]=' ';
				dwBuffSizeUsed=sizeof(MRA_FT_GET_FILE)+WideCharToMultiByte(MRA_CODE_PAGE,0,pmrafqFilesQueueItem->pmfqfFiles[i].lpwszName,pmrafqFilesQueueItem->pmfqfFiles[i].dwNameLen,(LPSTR)(btBuff+sizeof(MRA_FT_GET_FILE)),(SIZEOF(btBuff)-sizeof(MRA_FT_GET_FILE)),NULL,NULL);
				btBuff[dwBuffSizeUsed]=0;
				dwBuffSizeUsed++;

				if (dwBuffSizeUsed==Netlib_Send(pmrafqFilesQueueItem->hConnection,(LPSTR)btBuff,dwBuffSizeUsed,0))
				{// file request sended
					hFile=CreateFileW(wszFileName,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
					if (hFile!=INVALID_HANDLE_VALUE)
					{// file opened/created, pre allocating disk space, for best perfomance
						bOK=FALSE;

						liFileSize.QuadPart=(LONGLONG)pmrafqFilesQueueItem->pmfqfFiles[i].dwSize;
						if (SetFilePointerEx(hFile,liFileSize,NULL,FILE_BEGIN))
						if (SetEndOfFile(hFile))
						{
							liFileSize.QuadPart=0;
							bOK=SetFilePointerEx(hFile,liFileSize,NULL,FILE_BEGIN);
						}

						if (bOK)
						{// disk space pre allocated
							bOK=FALSE;
							bContinue=TRUE;
							dwUpdateTimeNext=GetTickCount();
							nls.dwTimeout=(1000*DB_Mra_GetDword(NULL,"TimeOutReceiveFileData",MRA_DEF_FS_TIMEOUT_RECV));
							nls.hReadConns[0]=pmrafqFilesQueueItem->hConnection;
							ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_DATA,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,(LPARAM)&pfts);

							while(bContinue)
							{
								switch(CallService(MS_NETLIB_SELECT,0,(LPARAM)&nls)) {
								case SOCKET_ERROR:
								case 0:// Time out
									dwRetErrorCode=GetLastError();
									ShowFormatedErrorMessage(L"Receive files: error on receive file data",dwRetErrorCode);
									bContinue=FALSE;
									break;
								case 1:
									dwReceived=Netlib_Recv(pmrafqFilesQueueItem->hConnection,(LPSTR)&btBuff,SIZEOF(btBuff),0);
									if (dwReceived==0 || dwReceived==SOCKET_ERROR)
									{
										dwRetErrorCode=GetLastError();
										ShowFormatedErrorMessage(L"Receive files: error on receive file data",dwRetErrorCode);
										bContinue=FALSE;
									}else{
										if (WriteFile(hFile,(LPVOID)&btBuff,dwReceived,&dwReceived,NULL))
										{
											pfts.currentFileProgress+=dwReceived;
											pfts.totalProgress+=dwReceived;
											
											// progress updates
											dwUpdateTimeCur=GetTickCount();
											if (dwUpdateTimeNext<=dwUpdateTimeCur || pfts.currentFileProgress>=pmrafqFilesQueueItem->pmfqfFiles[i].dwSize)
											{// we update it
												dwUpdateTimeNext=dwUpdateTimeCur+MRA_FILES_QUEUE_PROGRESS_INTERVAL;
												ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_DATA,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,(LPARAM)&pfts);

												if (pfts.currentFileProgress>=pmrafqFilesQueueItem->pmfqfFiles[i].dwSize)
												{// file received
													bOK=TRUE;
													bContinue=FALSE;
												}
											}
										}else{// err on write file
											dwRetErrorCode=GetLastError();
											ShowFormatedErrorMessage(L"Receive files: cant write file data, error",dwRetErrorCode);
											bContinue=FALSE;
										}
									}
									break;
								}
							}// end while
						}else{// err allocating file disk space
							dwRetErrorCode=GetLastError();
							mir_sntprintf(szErrorText,SIZEOF(szErrorText),TranslateW(L"Receive files: cant allocate disk space for file, size %lu bytes, error"),pmrafqFilesQueueItem->pmfqfFiles[i].dwSize);
							ShowFormatedErrorMessage(szErrorText,dwRetErrorCode);
						}
						CloseHandle(hFile);

						if (bOK==FALSE)
						{// file recv failed
							DeleteFileW(wszFileName);
							bFailed=TRUE;
							break;
						}
					}else{// err on open file
						dwRetErrorCode=GetLastError();
						mir_sntprintf(szErrorText,SIZEOF(szErrorText),TranslateW(L"Receive files: cant open file %s, error"),wszFileName);
						ShowFormatedErrorMessage(szErrorText,dwRetErrorCode);
						bFailed=TRUE;
						break;
					}
				}else{// err on send request for file
					dwRetErrorCode=GetLastError();
					mir_sntprintf(szErrorText,SIZEOF(szErrorText),TranslateW(L"Receive files: request for file %s not sended, error"),pmrafqFilesQueueItem->pmfqfFiles[i].lpwszName);
					ShowFormatedErrorMessage(szErrorText,NO_ERROR);
					bFailed=TRUE;
					break;
				}
			}// end for

			Netlib_CloseHandle(pmrafqFilesQueueItem->hConnection);
			pmrafqFilesQueueItem->hConnection=NULL;
		}

		if (bFailed)
		{
			CHAR szEMail[MAX_EMAIL_LEN];
			SIZE_T dwEMailSize;

			if (DB_Mra_GetStaticStringA(pmrafqFilesQueueItem->hContact,"e-mail",szEMail,SIZEOF(szEMail),&dwEMailSize))
			{
				MraSendCommand_FileTransferAck(FILE_TRANSFER_STATUS_ERROR,szEMail,dwEMailSize,pmrafqFilesQueueItem->dwIDRequest,NULL,0);
			}
			ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_FAILED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
		}else{
			ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_SUCCESS,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
		}

		ListMTLock(&pmrafqFilesQueue->lmtListMT);
		MraFilesQueueItemFree(pmrafqFilesQueueItem);
		ListMTUnLock(&pmrafqFilesQueue->lmtListMT);
	}
}



void MraFilesQueueSendThreadProc(LPVOID lpParameter)
{
	DWORD dwRetErrorCode=NO_ERROR;

	if (lpParameter)
	{
		MRA_FILES_QUEUE *pmrafqFilesQueue=(MRA_FILES_QUEUE*)((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->hFilesQueueHandle;
		MRA_FILES_QUEUE_ITEM *pmrafqFilesQueueItem=((MRA_FILES_THREADPROC_PARAMS*)lpParameter)->pmrafqFilesQueueItem;
	    
		CHAR szFileName[MAX_FILEPATH]={0};
		WCHAR szErrorText[2048];
		BYTE btBuff[BUFF_SIZE_RCV];
		BOOL bFailed=TRUE,bOK,bConnected=FALSE;
		DWORD dwReceived,dwSendBlockSize,dwUpdateTimeNext,dwUpdateTimeCur;
		HANDLE hFile;
		SIZE_T i,j,dwBuffSizeUsed=0;
		LPWSTR lpwszFileName;
		PROTOFILETRANSFERSTATUS pfts={0};

		MEMFREE(lpParameter);

		pfts.cbSize=sizeof(pfts);
		pfts.hContact=pmrafqFilesQueueItem->hContact;
		pfts.flags=(PFTS_SENDING|PFTS_UNICODE);// pfts.sending=pmrafqFilesQueueItem->bSending;	//true if sending, false if receiving
		//pfts.files;
		pfts.totalFiles=pmrafqFilesQueueItem->dwFilesCount;
		//pfts.currentFileNumber=0;
		pfts.totalBytes=pmrafqFilesQueueItem->dwFilesTotalSize;
		//pfts.totalProgress=0;
		pfts.wszWorkingDir=pmrafqFilesQueueItem->lpwszPath;
		//pfts.currentFile;
		//pfts.currentFileSize;
		//pfts.currentFileProgress;
		//pfts.currentFileTime;  //as seconds since 1970

		dwSendBlockSize=DB_Mra_GetDword(NULL,"FileSendBlockSize",MRA_DEFAULT_FILE_SEND_BLOCK_SIZE);
		if (dwSendBlockSize>SIZEOF(btBuff)) dwSendBlockSize=SIZEOF(btBuff);
		if (dwSendBlockSize<512) dwSendBlockSize=MRA_DEFAULT_FILE_SEND_BLOCK_SIZE;

		if (MraFilesQueueConnectIn(pmrafqFilesQueueItem))
		{
			bConnected=TRUE;
		}else{
			if (MraFilesQueueConnectOut(pmrafqFilesQueueItem))
			{
				bConnected=TRUE;
			}else{
				if (InterlockedExchangeAdd((volatile LONG*)&pmrafqFilesQueueItem->bIsWorking,0))
				{
					ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKRESULT_CONNECTPROXY,ACKRESULT_CONNECTED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
					if (MraMrimProxyConnect(pmrafqFilesQueueItem->hMraMrimProxyData,&pmrafqFilesQueueItem->hConnection)==NO_ERROR)
					{// ������������ � ������, ��������� �� �� ������ (��� ���, �� ���� ��� ����)
						if (MraFilesQueueHandCheck(pmrafqFilesQueueItem->hConnection,pmrafqFilesQueueItem))
						{// ����� ������������� � ��� ��� �����// pmrafqFilesQueueItem->bSending
							ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_CONNECTED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
							bConnected=TRUE;
						}
					}
				}
			}
		}

		if (bConnected)
		{// email verifyed
			bFailed=FALSE;
			for(i=0;i<pmrafqFilesQueueItem->dwFilesCount;i++)
			{// sending files
				ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_NEXTFILE,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);

				dwBuffSizeUsed=0;
				while(TRUE)
				{
					dwReceived=Netlib_Recv(pmrafqFilesQueueItem->hConnection,((LPSTR)btBuff+dwBuffSizeUsed),(SIZEOF(btBuff)-dwBuffSizeUsed),0);
					if (dwReceived==0 || dwReceived==SOCKET_ERROR)
					{// err on receive file name to send
						dwRetErrorCode=GetLastError();
						ShowFormatedErrorMessage(L"Send files: file send request not received, error",dwRetErrorCode);
						bFailed=TRUE;
						break;
					}else{
						dwBuffSizeUsed+=dwReceived;
						if (MemoryFindByte((dwBuffSizeUsed-dwReceived),btBuff,dwBuffSizeUsed,0)) break;
					}
				}// end while (file name passible received)*/


				if (bFailed==FALSE)
				{// ...received
					if (dwBuffSizeUsed>(sizeof(MRA_FT_GET_FILE)+1))
					{// file name received
						if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,(LPSTR)btBuff,(sizeof(MRA_FT_GET_FILE)-1),MRA_FT_GET_FILE,(sizeof(MRA_FT_GET_FILE)-1))==CSTR_EQUAL)
						{// MRA_FT_GET_FILE verifyed
							bFailed=TRUE;
							for(j=0;j<pmrafqFilesQueueItem->dwFilesCount;j++)
							{
								lpwszFileName=GetFileNameFromFullPathW(pmrafqFilesQueueItem->pmfqfFiles[j].lpwszName,pmrafqFilesQueueItem->pmfqfFiles[j].dwNameLen);
								szFileName[WideCharToMultiByte(MRA_CODE_PAGE,0,lpwszFileName,(pmrafqFilesQueueItem->pmfqfFiles[j].dwNameLen-(lpwszFileName-pmrafqFilesQueueItem->pmfqfFiles[j].lpwszName)),szFileName,SIZEOF(szFileName),NULL,NULL)]=0;

								if (CompareStringA(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NORM_IGNORECASE,(((LPSTR)btBuff)+sizeof(MRA_FT_GET_FILE)),(dwBuffSizeUsed-(sizeof(MRA_FT_GET_FILE)+1)),szFileName,-1)==CSTR_EQUAL)
								{
									bFailed=FALSE;
									break;
								}
							}

							if (bFailed==FALSE)
							{
								hFile=CreateFileW(pmrafqFilesQueueItem->pmfqfFiles[j].lpwszName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,(FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN),NULL);
								if (hFile!=INVALID_HANDLE_VALUE)
								{
									bOK=FALSE;
									dwUpdateTimeNext=GetTickCount();
									pfts.currentFileNumber=i;
									pfts.wszCurrentFile=pmrafqFilesQueueItem->pmfqfFiles[j].lpwszName;
									pfts.currentFileSize=pmrafqFilesQueueItem->pmfqfFiles[j].dwSize;
									pfts.currentFileProgress=0;
									//pfts.currentFileTime;  //as seconds since 1970

									WideCharToMultiByte(MRA_CODE_PAGE,0,pmrafqFilesQueueItem->pmfqfFiles[j].lpwszName,pmrafqFilesQueueItem->pmfqfFiles[j].dwNameLen,szFileName,SIZEOF(szFileName),NULL,NULL);
									ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_DATA,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,(LPARAM)&pfts);

									while(TRUE)
									{// read and sending
										if (ReadFile(hFile,btBuff,dwSendBlockSize,(DWORD*)&dwBuffSizeUsed,NULL))
										{
											dwReceived=Netlib_Send(pmrafqFilesQueueItem->hConnection,(LPSTR)btBuff,dwBuffSizeUsed,0);
											if (dwBuffSizeUsed==dwReceived)
											{
												pfts.currentFileProgress+=dwBuffSizeUsed;
												pfts.totalProgress+=dwBuffSizeUsed;
												
												// progress updates
												dwUpdateTimeCur=GetTickCount();
												if (dwUpdateTimeNext<=dwUpdateTimeCur || pfts.currentFileProgress>=pmrafqFilesQueueItem->pmfqfFiles[j].dwSize)
												{// we update it
													dwUpdateTimeNext=dwUpdateTimeCur+MRA_FILES_QUEUE_PROGRESS_INTERVAL;

													ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_DATA,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,(LPARAM)&pfts);
													
													if (pfts.currentFileProgress>=pmrafqFilesQueueItem->pmfqfFiles[j].dwSize)
													{// file received
														bOK=TRUE;
														break;
													}
												}
											}else{// err on send file data
												dwRetErrorCode=GetLastError();
												ShowFormatedErrorMessage(L"Send files: error on send file data",dwRetErrorCode);
												break;
											}
										}else{// read failure
											dwRetErrorCode=GetLastError();
											ShowFormatedErrorMessage(L"Send files: cant read file data, error",dwRetErrorCode);
											break;
										}
									}// end while
									CloseHandle(hFile);

									if (bOK==FALSE)
									{// file recv failed
										bFailed=TRUE;
										break;
									}
								}else{// err on open file
									dwRetErrorCode=GetLastError();

									mir_sntprintf(szErrorText,SIZEOF(szErrorText),TranslateW(L"Send files: cant open file %s, error"),pmrafqFilesQueueItem->pmfqfFiles[j].lpwszName);
									ShowFormatedErrorMessage(szErrorText,dwRetErrorCode);
									bFailed=TRUE;
									break;
								}
							}else{
								mir_sntprintf(szErrorText,SIZEOF(szErrorText),TranslateW(L"Send files: requested file: %S - not found in send files list."),(((LPSTR)btBuff)+sizeof(MRA_FT_GET_FILE)));
								ShowFormatedErrorMessage(szErrorText,NO_ERROR);
								bFailed=TRUE;
								break;
							}
						}else{// err on receive, trash
							ShowFormatedErrorMessage(L"Send files: bad file send request - invalid header",NO_ERROR);
							bFailed=TRUE;
							break;
						}
					}else{// bad file name or trash
						ShowFormatedErrorMessage(L"Send files: bad file send request - to small packet",NO_ERROR);
						bFailed=TRUE;
						break;
					}
				}else{
					break;
				}
			}// end for

			Netlib_CloseHandle(pmrafqFilesQueueItem->hConnection);
			pmrafqFilesQueueItem->hConnection=NULL;
		}

		if (bFailed)
		{
			CHAR szEMail[MAX_EMAIL_LEN];
			SIZE_T dwEMailSize;

			if (DB_Mra_GetStaticStringA(pmrafqFilesQueueItem->hContact,"e-mail",szEMail,SIZEOF(szEMail),&dwEMailSize))
			{
				MraSendCommand_FileTransferAck(FILE_TRANSFER_STATUS_ERROR,szEMail,dwEMailSize,pmrafqFilesQueueItem->dwIDRequest,NULL,0);
			}
			ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_FAILED,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
		}else{
			ProtoBroadcastAck(PROTOCOL_NAMEA,pmrafqFilesQueueItem->hContact,ACKTYPE_FILE,ACKRESULT_SUCCESS,(HANDLE)pmrafqFilesQueueItem->dwIDRequest,0);
		}

		ListMTLock(&pmrafqFilesQueue->lmtListMT);
		MraFilesQueueItemFree(pmrafqFilesQueueItem);
		ListMTUnLock(&pmrafqFilesQueue->lmtListMT);
	}
}