#include "Mra.h"
#include "MraOfflineMsg.h"
#include "MraConstans.h"


#define LF			"\n"
#define LFLF		"\n\n"
#define CRLF		"\r\n"
#define CRLFCRLF	"\r\n\r\n"


DWORD MraOfflineMessageGetMIMEHeadAndBody	(LPSTR lpszMessage,SIZE_T dwMessageSize,LPSTR *plpszHeader,SIZE_T *pdwHeaderSize,LPSTR *plpszBody,SIZE_T *pdwBodySize);
DWORD MraOfflineMessageGetNextMIMEPart		(LPSTR lpszBody,SIZE_T dwBodySize,LPSTR lpszBoundary,SIZE_T dwBoundarySize,LPSTR *plpszCurMIMEPos,LPSTR *plpszMIMEPart,SIZE_T *pdwMIMEPartSize);
DWORD MraOfflineMessageGetHeaderValue		(LPSTR lpszHeader,LPSTR lpszHeaderLow,SIZE_T dwHeaderSize,LPSTR lpszValueName,SIZE_T dwValueNameSize,LPSTR *plpszValue,SIZE_T *pdwValueSize);
DWORD MraOfflineMessageGetHeaderValueLow	(LPSTR lpszHeaderLow,SIZE_T dwHeaderSize,LPSTR lpszValueName,SIZE_T dwValueNameSize,LPSTR *plpszValue,SIZE_T *pdwValueSize);
DWORD MraOfflineMessageConvertTime			(INTERNET_TIME *pitTime);




DWORD MraOfflineMessageGet(MRA_LPS *plpsMsg,DWORD *pdwTime,DWORD *pdwFlags,MRA_LPS *plpsEMail,MRA_LPS *plpsText,MRA_LPS *plpsRTFText,MRA_LPS *plpsMultiChatData,LPBYTE *plpbBuff)
{// ���������
	DWORD dwRetErrorCode=ERROR_INVALID_HANDLE;


	if (plpsMsg)
	if (plpsMsg->lpszData && plpsMsg->dwSize)
	{
		LPSTR lpszHeader,lpszHeaderLow,lpszBody,lpszContentTypeLow,lpszTemp;
		SIZE_T dwHeaderSize,dwBodySize,dwContentTypeSize,dwTempSize;
		DWORD dwMultichatType;

		#ifdef _DEBUG
			DebugPrintCRLFA(plpsMsg->lpszData);
		#endif

		if (MraOfflineMessageGetMIMEHeadAndBody(plpsMsg->lpszData,plpsMsg->dwSize,&lpszHeader,&dwHeaderSize,&lpszBody,&dwBodySize)==NO_ERROR)
		{
			lpszHeaderLow=(LPSTR)MEMALLOC(dwHeaderSize);
			if (lpszHeaderLow) BuffToLowerCase(lpszHeaderLow,lpszHeader,dwHeaderSize);

			if (pdwTime)
			if (MraOfflineMessageGetHeaderValue(lpszHeader,lpszHeaderLow,dwHeaderSize,"date",4,&lpszTemp,&dwTempSize)==NO_ERROR)
			{
				INTERNET_TIME itTime;
				InternetTimeGetTime(lpszTemp,dwTempSize,&itTime);
				(*pdwTime)=MraOfflineMessageConvertTime(&itTime);
			}else{
				(*pdwTime)=0;
			}

			if (pdwFlags)
			if (MraOfflineMessageGetHeaderValue(lpszHeader,lpszHeaderLow,dwHeaderSize,"x-mrim-flags",12,&lpszTemp,&dwTempSize)==NO_ERROR)
			{
				(*pdwFlags)=StrHexToUNum32(lpszTemp,dwTempSize);
			}else{
				(*pdwFlags)=0;
			}

			if (MraOfflineMessageGetHeaderValue(lpszHeader,lpszHeaderLow,dwHeaderSize,"x-mrim-multichat-type",21,&lpszTemp,&dwTempSize)==NO_ERROR)
			{
				dwMultichatType=StrHexToUNum32(lpszTemp,dwTempSize);
			}else{
				dwMultichatType=0;
			}


			if (plpsEMail)
			if (MraOfflineMessageGetHeaderValue(lpszHeader,lpszHeaderLow,dwHeaderSize,"from",4,&plpsEMail->lpszData,&plpsEMail->dwSize)!=NO_ERROR)
			{
				plpsEMail->lpszData=NULL;
				plpsEMail->dwSize=0;
			}


			if (plpsText)
			{
				plpsText->lpszData=NULL;
				plpsText->dwSize=0;
			}
			if (plpsRTFText)
			{
				plpsRTFText->lpszData=NULL;
				plpsRTFText->dwSize=0;
			}
			if (plpsMultiChatData)
			{
				plpsMultiChatData->lpszData=NULL;
				plpsMultiChatData->dwSize=0;
			}
			if (plpbBuff) (*plpbBuff)=NULL;

			if (plpsText || plpsRTFText)
			if (MraOfflineMessageGetHeaderValueLow(lpszHeaderLow,dwHeaderSize,"content-type",12,&lpszContentTypeLow,&dwContentTypeSize)==NO_ERROR)
			{

				if (MemoryFind(0,lpszContentTypeLow,dwContentTypeSize,"multipart/alternative",21))
				{// Content-Type: multipart/alternative; boundary=1217508709J3777283291217508709T31197726
					LPSTR lpszBoundary,lpszMIMEPart,lpszCurMIMEPos,lpszMIMEHeader,lpszMIMEHeaderLow,lpszMIMEBody,lpszMIMEContentType;
					SIZE_T i,dwBoundarySize,dwMIMEPartSize,dwMIMEHeaderSize,dwMIMEBodySize,dwMIMEContentTypeSize;

					lpszBoundary=(LPSTR)MemoryFind(0,lpszContentTypeLow,dwContentTypeSize,"boundary=",9);
					if (lpszBoundary)
					{
						dwBoundarySize=((dwContentTypeSize-(lpszBoundary-lpszContentTypeLow))-9);
						lpszBoundary=(lpszHeader+((lpszBoundary+9)-lpszHeaderLow));

						i=0;
						lpszCurMIMEPos=lpszBody;
						while(MraOfflineMessageGetNextMIMEPart(lpszBody,dwBodySize,lpszBoundary,dwBoundarySize,&lpszCurMIMEPos,&lpszMIMEPart,&dwMIMEPartSize)==NO_ERROR)
						{
							if (MraOfflineMessageGetMIMEHeadAndBody(lpszMIMEPart,dwMIMEPartSize,&lpszMIMEHeader,&dwMIMEHeaderSize,&lpszMIMEBody,&dwMIMEBodySize)==NO_ERROR)
							{
								lpszMIMEHeaderLow=(LPSTR)MEMALLOC(dwMIMEHeaderSize);
								if (lpszMIMEHeaderLow)
								{
									BuffToLowerCase(lpszMIMEHeaderLow,lpszMIMEHeader,dwMIMEHeaderSize);
									if (MraOfflineMessageGetHeaderValueLow(lpszMIMEHeaderLow,dwMIMEHeaderSize,"content-type",12,&lpszMIMEContentType,&dwMIMEContentTypeSize)==NO_ERROR)
									{
										if (MemoryFind(0,lpszMIMEContentType,dwMIMEContentTypeSize,"text/plain",10))
										{// this is simple text part: text/plain
											if (plpsText)
											{
												if (MemoryFind(0,lpszMIMEContentType,dwMIMEContentTypeSize,"utf-16le",8))
												{// charset=UTF-16LE// ������������ ��� ��� � base64
													if (plpbBuff)
													{// ������ ��� ������������� ������ ����� ��������
														LPWSTR lpwszText;
														SIZE_T dwTextSize;

														lpwszText=(LPWSTR)MEMALLOC(dwMIMEBodySize);
														if (lpwszText)
														{
															BASE64DecodeFormated(lpszMIMEBody,dwMIMEBodySize,lpwszText,dwMIMEBodySize,&dwTextSize);
															plpsText->lpwszData=lpwszText;
															plpsText->dwSize=dwTextSize;
															if (pdwFlags)
															{
																(*pdwFlags)|=MESSAGE_FLAG_v1p16; // set unocode flag if not exist
																(*pdwFlags)&=~MESSAGE_FLAG_CP1251; // reset ansi flag if exist
															}
															(*plpbBuff)=(LPBYTE)lpwszText;
															dwRetErrorCode=NO_ERROR;
														}
													}
												}else
												if (MemoryFind(0,lpszMIMEContentType,dwMIMEContentTypeSize,"cp-1251",7))
												{// charset=CP-1251
													plpsText->lpszData=lpszMIMEBody;
													plpsText->dwSize=dwMIMEBodySize;
													if (pdwFlags)
													{
														(*pdwFlags)&=~MESSAGE_FLAG_v1p16; // reset unocode flag if exist
														(*pdwFlags)|=MESSAGE_FLAG_CP1251; // set ansi flag 
													}
													dwRetErrorCode=NO_ERROR;
												}else{
													DebugBreak();
												}
											}
										}else
										if (MemoryFind(0,lpszMIMEContentType,dwMIMEContentTypeSize,"application/x-mrim-rtf",22))
										{
											if (plpsRTFText)
											{
												plpsRTFText->lpszData=lpszMIMEBody;
												plpsRTFText->dwSize=dwMIMEBodySize;
												if (pdwFlags) (*pdwFlags)|=MESSAGE_FLAG_RTF; // set RTF flag if not exist
												dwRetErrorCode=NO_ERROR;
											}
										}else
										if (MemoryFind(0,lpszMIMEContentType,dwMIMEContentTypeSize,"application/x-mrim+xml",22))
										{
											if (plpsMultiChatData)
											{
												plpsMultiChatData->lpszData=lpszMIMEBody;
												plpsMultiChatData->dwSize=dwMIMEBodySize;
												if (pdwFlags) (*pdwFlags)|=MESSAGE_FLAG_MULTICHAT; // set MESSAGE_FLAG_MULTICHAT flag if not exist
												dwRetErrorCode=NO_ERROR;
											}
										}else{
											DebugBreak();
										}
									}
									MEMFREE(lpszMIMEHeaderLow);
								}
							}
							i++;
						}

						DebugBreakIf((i>3 || i==0));
					}else{// boundary not found
						DebugBreak();
					}
				}else
				if (MemoryFind(0,lpszContentTypeLow,dwContentTypeSize,"text/plain",10))
				{// Content-Type: text/plain; charset=CP-1251
					if (MemoryFind(0,lpszContentTypeLow,dwContentTypeSize,"utf-16le",8))
					{// charset=UTF-16LE// ������������ ��� ��� � base64
						if (plpbBuff)
						{// ������ ��� ������������� ������ ����� ��������
							LPWSTR lpwszText;
							SIZE_T dwTextSize;

							lpwszText=(LPWSTR)MEMALLOC(dwBodySize);
							if (lpwszText)
							{
								BASE64DecodeFormated(lpszBody,dwBodySize,lpwszText,dwBodySize,&dwTextSize);
								plpsText->lpwszData=lpwszText;
								plpsText->dwSize=dwTextSize;
								if (pdwFlags)
								{
									(*pdwFlags)|=MESSAGE_FLAG_v1p16; // set unocode flag if not exist
									(*pdwFlags)&=~MESSAGE_FLAG_CP1251; // reset ansi flag if exist
								}
								(*plpbBuff)=(LPBYTE)lpwszText;
								dwRetErrorCode=NO_ERROR;
							}
						}
					}else
					if (MemoryFind(0,lpszContentTypeLow,dwContentTypeSize,"cp-1251",7))
					{// charset=CP-1251
						plpsText->lpszData=lpszBody;
						plpsText->dwSize=dwBodySize;
						if (pdwFlags)
						{
							(*pdwFlags)&=~MESSAGE_FLAG_v1p16; // reset unocode flag if exist
							(*pdwFlags)|=MESSAGE_FLAG_CP1251; // set ansi flag 
						}
						dwRetErrorCode=NO_ERROR;
					}else{
						DebugBreak();
					}
				}else
				if (MemoryFind(0,lpszContentTypeLow,dwContentTypeSize,"application/x-mrim-auth-req",27))
				{// Content-Type: application/x-mrim-auth-req
					if (plpsText)
					{
						plpsText->lpszData=lpszBody;
						plpsText->dwSize=dwBodySize;
					}
					dwRetErrorCode=NO_ERROR;
				}else{
					DebugBreak();
				}
			}else{
				DebugBreak();
			}

			MEMFREE(lpszHeaderLow);
		}
	}

return(dwRetErrorCode);
}


DWORD MraOfflineMessageGetMIMEHeadAndBody(LPSTR lpszMessage,SIZE_T dwMessageSize,LPSTR *plpszHeader,SIZE_T *pdwHeaderSize,LPSTR *plpszBody,SIZE_T *pdwBodySize)
{
	DWORD dwRetErrorCode=ERROR_NOT_FOUND;

	if (lpszMessage && dwMessageSize)
	{
		LPSTR lpszBody;
		SIZE_T dwBodySize;
		
		// �������: ���� �� �������������� RFC � ������ CRLFCRLF ������ LFLF � MIME ������, ������ ������
		lpszBody=(LPSTR)MemoryFind(0,lpszMessage,dwMessageSize,CRLFCRLF,(sizeof(CRLFCRLF)-1));
		if (lpszBody)
		{
			lpszBody+=(sizeof(CRLFCRLF)-1);
		}else{
			lpszBody=(LPSTR)MemoryFind(0,lpszMessage,dwMessageSize,LFLF,(sizeof(LFLF)-1));
			if (lpszBody) lpszBody+=(sizeof(LFLF)-1);
		}

		if (lpszBody)
		{// ����� ������ �������� ���� �����
			dwBodySize=(dwMessageSize-(lpszBody-lpszMessage));

			if (plpszHeader)	(*plpszHeader)=lpszMessage;
			if (pdwHeaderSize)	(*pdwHeaderSize)=((lpszBody-(sizeof(LFLF)-1))-lpszMessage);
			if (plpszBody)		(*plpszBody)=lpszBody;
			if (pdwBodySize)	(*pdwBodySize)=dwBodySize;

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


DWORD MraOfflineMessageGetNextMIMEPart(LPSTR lpszBody,SIZE_T dwBodySize,LPSTR lpszBoundary,SIZE_T dwBoundarySize,LPSTR *plpszCurMIMEPos,LPSTR *plpszMIMEPart,SIZE_T *pdwMIMEPartSize)
{
	DWORD dwRetErrorCode=ERROR_NOT_FOUND;

	if (lpszBody && dwBodySize)
	{
		LPSTR lpszMIMEPart,lpszCurMIMEPos,lpszTemp;
		SIZE_T dwMIMEPartSize;

		if (plpszCurMIMEPos) lpszCurMIMEPos=(*plpszCurMIMEPos);
		lpszMIMEPart=(LPSTR)MemoryFind((lpszCurMIMEPos-lpszBody),lpszBody,dwBodySize,lpszBoundary,dwBoundarySize);
		if (lpszMIMEPart)
		{// ������ ���� �����
			lpszMIMEPart+=dwBoundarySize;

			// �������: ���� �� �������������� RFC � ������ CRLF ������ LF � MIME ������, ������ ������
			if ((*((WORD*)lpszMIMEPart))==(*((WORD*)CRLF)))
			{
				lpszMIMEPart+=(sizeof(CRLF)-1);
			}else
			if ((*((BYTE*)lpszMIMEPart))==(*((BYTE*)LF)))
			{
				lpszMIMEPart+=(sizeof(LF)-1);
			}else
			if ((*((WORD*)lpszMIMEPart))=='--')
			{
				lpszMIMEPart=NULL;
			}else{
				DebugBreak();
			}

			if (lpszMIMEPart)
			{
				lpszTemp=(LPSTR)MemoryFind((lpszMIMEPart-lpszBody),lpszBody,dwBodySize,lpszBoundary,dwBoundarySize);
				if (lpszTemp)
				{// ����� ����� ���� ����� � �������
					dwMIMEPartSize=(lpszTemp-lpszMIMEPart);// 4=CRLF"--"Boundary / 3=LF"--"Boundary
					// �������: ���� �� �������������� RFC � ������ CRLF ������ LF � MIME ������, ������ ������
					if ((*((WORD*)(lpszTemp-4)))==(*((WORD*)CRLF)))
					{
						dwMIMEPartSize-=4;
					}else
					if ((*((BYTE*)(lpszTemp-3)))==(*((BYTE*)LF)))
					{
						dwMIMEPartSize-=3;
					}else{
						DebugBreak();
					}

					if (plpszMIMEPart) (*plpszMIMEPart)=lpszMIMEPart;
					if (pdwMIMEPartSize) (*pdwMIMEPartSize)=dwMIMEPartSize;
					if (plpszCurMIMEPos) (*plpszCurMIMEPos)=lpszTemp;
					dwRetErrorCode=NO_ERROR;
				}
			}else{
				dwRetErrorCode=ERROR_NO_MORE_ITEMS;
			}
		}
	}else{
		dwRetErrorCode=ERROR_INVALID_HANDLE;
	}
return(dwRetErrorCode);
}


DWORD MraOfflineMessageGetHeaderValue(LPSTR lpszHeader,LPSTR lpszHeaderLow,SIZE_T dwHeaderSize,LPSTR lpszValueName,SIZE_T dwValueNameSize,LPSTR *plpszValue,SIZE_T *pdwValueSize)
{
	DWORD dwRetErrorCode=ERROR_NOT_FOUND;
	LPSTR lpszValue,lpszValueEnd;
	SIZE_T dwValueSize;

	lpszValue=(LPSTR)MemoryFind(0,lpszHeaderLow,dwHeaderSize,lpszValueName,dwValueNameSize);
	if (lpszValue)
	{
		lpszValue+=dwValueNameSize;
		lpszValueEnd=(LPSTR)MemoryFind((lpszValue-lpszHeaderLow),lpszHeaderLow,dwHeaderSize,CRLF,(sizeof(CRLF)-1));
		if (lpszValueEnd==NULL) lpszValueEnd=(LPSTR)MemoryFind((lpszValue-lpszHeaderLow),lpszHeaderLow,dwHeaderSize,LF,(sizeof(LF)-1));
		if (lpszValueEnd==NULL) lpszValueEnd=(LPSTR)(lpszHeaderLow+dwHeaderSize);

		lpszValue=(LPSTR)MemoryFind((lpszValue-lpszHeaderLow),lpszHeaderLow,(lpszValueEnd-lpszHeaderLow),":",1);
		if (lpszValue)
		{
			lpszValue++;
			dwValueSize=(lpszValueEnd-lpszValue);
			SkeepSPWSP((lpszHeader+(lpszValue-lpszHeaderLow)),dwValueSize,plpszValue,pdwValueSize);
			dwRetErrorCode=NO_ERROR;
		}
	}
return(dwRetErrorCode);
}


DWORD MraOfflineMessageGetHeaderValueLow(LPSTR lpszHeaderLow,SIZE_T dwHeaderSize,LPSTR lpszValueName,SIZE_T dwValueNameSize,LPSTR *plpszValue,SIZE_T *pdwValueSize)
{
	DWORD dwRetErrorCode=ERROR_NOT_FOUND;
	LPSTR lpszValue,lpszValueEnd;
	SIZE_T dwValueSize;

	lpszValue=(LPSTR)MemoryFind(0,lpszHeaderLow,dwHeaderSize,lpszValueName,dwValueNameSize);
	if (lpszValue)
	{
		lpszValue+=dwValueNameSize;
		lpszValueEnd=(LPSTR)MemoryFind((lpszValue-lpszHeaderLow),lpszHeaderLow,dwHeaderSize,CRLF,(sizeof(CRLF)-1));
		if (lpszValueEnd==NULL) lpszValueEnd=(LPSTR)MemoryFind((lpszValue-lpszHeaderLow),lpszHeaderLow,dwHeaderSize,LF,(sizeof(LF)-1));
		if (lpszValueEnd==NULL) lpszValueEnd=(LPSTR)(lpszHeaderLow+dwHeaderSize);

		lpszValue=(LPSTR)MemoryFind((lpszValue-lpszHeaderLow),lpszHeaderLow,(lpszValueEnd-lpszHeaderLow),":",1);
		if (lpszValue)
		{
			lpszValue++;
			dwValueSize=(lpszValueEnd-lpszValue);
			SkeepSPWSP(lpszValue,dwValueSize,plpszValue,pdwValueSize);
			dwRetErrorCode=NO_ERROR;
		}
	}
return(dwRetErrorCode);
}


DWORD MraOfflineMessageConvertTime(INTERNET_TIME *pitTime)
{
	SYSTEMTIME stTime,stUniversalTime;
	TIME_ZONE_INFORMATION tziTimeZoneMailRu={0},tziTimeZoneLocal;

	GetTimeZoneInformation(&tziTimeZoneLocal);
	if (GetTimeZoneInformation(&tziTimeZoneMailRu)==TIME_ZONE_ID_DAYLIGHT) tziTimeZoneMailRu.DaylightBias*=2;
	tziTimeZoneMailRu.Bias=MAILRU_SERVER_TIME_ZONE;

	//TzSpecificLocalTimeToSystemTime(&tziTimeZoneMailRu,&pitTime->stTime,&stUniversalTime);
	{// for win 2000 compatible
		tziTimeZoneMailRu.Bias=-tziTimeZoneMailRu.Bias;
		tziTimeZoneMailRu.DaylightBias=-tziTimeZoneMailRu.DaylightBias;
		SystemTimeToTzSpecificLocalTime(&tziTimeZoneMailRu,&pitTime->stTime,&stUniversalTime);
	}//*/
	SystemTimeToTzSpecificLocalTime(&tziTimeZoneLocal,&stUniversalTime,&stTime);

return((DWORD)MakeTime32FromLocalSystemTime(&stTime));
}