#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)mir_calloc(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)mir_calloc(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) { // буффер для декодирования текста можно выделять LPS2ANSI(szMime, lpszMIMEBody, dwMIMEBodySize); unsigned dwTextSize; LPWSTR lpwszText = (LPWSTR)mir_base64_decode(szMime, &dwTextSize); if (lpwszText) { 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(); } mir_free(lpszMIMEHeaderLow); } } i++; } DebugBreakIf((i>3 || i == 0)); } else DebugBreak(); // boundary not found } 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) { // буфер для декодирования текста можно выделять LPS2ANSI(szMime, lpszBody, dwBodySize); unsigned dwTextSize; LPWSTR lpwszText = (LPWSTR)mir_base64_decode(szMime, &dwTextSize); if (lpwszText) { 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(); } mir_free(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)); }