From de40f3be3f08487937525c2ef096dad665dda61d Mon Sep 17 00:00:00 2001 From: dartraiden Date: Sat, 14 Jan 2023 01:30:59 +0300 Subject: Convert sources to CR+LF --- protocols/YAMN/src/mails/decode.cpp | 1068 +++++++++++++-------------- protocols/YAMN/src/mails/mails.cpp | 946 ++++++++++++------------ protocols/YAMN/src/mails/mime.cpp | 1390 +++++++++++++++++------------------ 3 files changed, 1702 insertions(+), 1702 deletions(-) (limited to 'protocols/YAMN/src/mails') diff --git a/protocols/YAMN/src/mails/decode.cpp b/protocols/YAMN/src/mails/decode.cpp index 414edfce60..7306376c2e 100644 --- a/protocols/YAMN/src/mails/decode.cpp +++ b/protocols/YAMN/src/mails/decode.cpp @@ -1,534 +1,534 @@ -/* - * This code implements decoding encoded MIME header in style - * =?iso-8859-2?Q? "User using email in central Europe characters such as =E9" ?= - * - * (c) majvan 2002-2004 - */ -#include "../stdafx.h" -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -struct _tcptable CodePageNamesAll[]= -{ - { "ANSI", "",TRUE,CP_ACP}, - { "WINDOWS-1", "250",0,1250}, - { "WINDOWS-1", "251",0,1251}, - { "WINDOWS-1", "252",0,1252}, - { "WINDOWS-1", "253",0,1253}, - { "WINDOWS-1", "254",0,1254}, - { "WINDOWS-1", "255",0,1255}, - { "WINDOWS-1", "256",0,1256}, - { "WINDOWS-1", "257",0,1257}, - { "WINDOWS-1", "258",0,1258}, - { "CP1", "250",0,1250}, - { "CP1", "251",0,1251}, - { "CP1", "252",0,1252}, - { "CP1", "253",0,1253}, - { "CP1", "254",0,1254}, - { "CP1", "255",0,1255}, - { "CP1", "256",0,1256}, - { "CP1", "257",0,1257}, - { "CP1", "258",0,1258}, - { "ANSI-1", "250",0,1250}, - { "ANSI-1", "251",0,1251}, - { "ANSI-1", "252",0,1252}, - { "ANSI-1", "253",0,1253}, - { "ANSI-1", "254",0,1254}, - { "ANSI-1", "255",0,1255}, - { "ANSI-1", "256",0,1256}, - { "ANSI-1", "257",0,1257}, - { "ANSI-1", "258",0,1258}, - { "KOI8", "-R",0,20866}, - { "KOI8", "",0,20866}, - { "KOI8", "-U",0,21866}, - { "KOI8", "-RU",0,21866}, - { "US-", "ASCII",0,20127}, - { "CP", "367",0,20127}, - { "ASCII", "",0,20127}, - { "ASCII", "7",0,20127}, - { "ISO-8859", "-1",0,28591}, - { "ISO-8859", "-2",0,28592}, - { "ISO-8859", "-3",0,28593}, - { "ISO-8859", "-4",0,28594}, - { "ISO-8859", "-5",0,28595}, - { "ISO-8859", "-6",0,28596}, - { "ISO-8859", "-7",0,28597}, - { "ISO-8859", "-8",0,28598}, - { "ISO-8859", "-9",0,28599}, - { "ISO-8859", "-15",0,28605}, - { "ISO_8859", "-1",0,28591}, - { "ISO_8859", "-2",0,28592}, - { "ISO_8859", "-3",0,28593}, - { "ISO_8859", "-4",0,28594}, - { "ISO_8859", "-5",0,28595}, - { "ISO_8859", "-6",0,28596}, - { "ISO_8859", "-7",0,28597}, - { "ISO_8859", "-8",0,28598}, - { "ISO_8859", "-9",0,28599}, - { "ISO_8859", "-15",0,28605}, - { "ISO-", "10646-USC2",0,1200}, - { "ISO-2022", "/2-JP",0,50220}, - { "ISO-2022", "-JP",0,50221}, - { "ISO-2022", "/JIS-JP",0,50222}, - { "ISO-2022", "-KR",0,50225}, - { "ISO-2022", "-CH(SP)",0,50227}, - { "ISO-2022", "-CH(TR)",0,50229}, - { "UTF-", "7",0,65000}, - { "UTF-", "8",0,65001}, - { "ARAB-", "TRANSPARENT",0,710}, - { "ASMO-", "TRANSPARENT",0,720}, - { "ASMO-", "449",0,709}, - { "ASMO-", "708",0,708}, - { "BIG5", "",0,950}, - { "EUC-", "CH(SP)",0,51936}, - { "EUC-", "CH(TR)",0,51950}, - { "EUC-", "JP",0,51932}, - { "EUC-", "KR",0,51949}, - { "GB-", "2312",0,20936}, - { "GB", "2312",0,20936}, - { "HZGB-", "2312",0,52936}, - { "IBM-", "037",0,37}, - { "IBM-", "290",0,290}, - { "IBM-", "437",0,437}, - { "IBM-", "500",0,500}, - { "IBM-", "775",0,775}, - { "IBM-", "850",0,850}, - { "IBM-", "852",0,852}, - { "IBM-", "855",0,855}, - { "IBM-", "857",0,857}, - { "IBM-", "860",0,860}, - { "IBM-", "861",0,861}, - { "IBM-", "862",0,862}, - { "IBM-", "863",0,863}, - { "IBM-", "864",0,864}, - { "IBM-", "865",0,865}, - { "IBM-", "866",0,866}, - { "IBM-", "869",0,869}, - { "IBM-", "870",0,870}, - { "IBM-", "875",0,875}, - { "IBM-", "1026",0,1026}, - { "IBM-", "273",0,20273}, - { "IBM-", "277",0,20277}, - { "IBM-", "278",0,20278}, - { "IBM-", "280",0,20280}, - { "IBM-", "284",0,20284}, - { "IBM-", "285",0,20285}, - { "IBM-", "290",0,20290}, - { "IBM-", "297",0,20297}, - { "IBM-", "420",0,20420}, - { "IBM-", "423",0,20423}, - { "IBM-", "871",0,20871}, - { "IBM-", "880",0,20880}, - { "IBM-", "905",0,20905}, - { "IBM-", "THAI",0,20838}, - { "ISCII-", "DEVANAGARI",0,57002}, - { "ISCII-", "BENGALI",0,57003}, - { "ISCII-", "TAMIL",0,57004}, - { "ISCII-", "TELUGU",0,57005}, - { "ISCII-", "ASSAMESE",0,57006}, - { "ISCII-", "ORIYA",0,57007}, - { "ISCII-", "KANNADA",0,57008}, - { "ISCII-", "MALAYALAM",0,57009}, - { "ISCII-", "GUJARATI",0,57010}, - { "ISCII-", "PUNJABI",0,57011}, - { "KOR-", "JOHAB",0,1361}, - { "KSC-", "5601",0,1361}, - { "MAC-", "ROMAN",0,10000}, - { "MAC-", "JP",0,10001}, - { "MAC-", "CH(SP)(BIG5)",0,10002}, - { "MAC-", "KR",0,10003}, - { "MAC-", "AR",0,10004}, - { "MAC-", "HW",0,10005}, - { "MAC-", "GR",0,10006}, - { "MAC-", "CY",0,10007}, - { "MAC-", "CH(SP)(GB2312)",0,10008}, - { "MAC-", "ROMANIA",0,10010}, - { "MAC-", "UA",0,10017}, - { "MAC-", "TH",0,10021}, - { "MAC-", "LAT2",0,10029}, - { "MAC-", "ICE",0,10079}, - { "MAC-", "TR",0,10081}, - { "MAC-", "CR",0,10082} -}; - -int CPLENALL = _countof(CodePageNamesAll); -struct _tcptable *CodePageNamesSupp; -int CPLENSUPP = 1; - -//Gets codepage ID from string representing charset such as "iso-8859-1" -// input- the string -// size- max length of input string -int GetCharsetFromString(char *input, size_t size); - -//HexValue to DecValue ('a' to 10) -// HexValue- hexa value ('a') -// DecValue- poiner where to store dec value -// returns 0 if not success -int FromHexa(char HexValue, char *DecValue); - -//Decodes a char from Base64 -// Base64Value- input char in Base64 -// DecValue- pointer where to store the result -// returns 0 if not success -int FromBase64(char Base64Value, char *DecValue); - -//Decodes string in quoted printable -// Src- input string -// Dst- where to store output string -// DstLen- how max long should be output string -// isQ- if is "Q-encoding" modification. should be TRUE in headers -// always returns 1 -int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ); - -//Decodes string in base64 -// Src- input string -// Dst- where to store output string -// DstLen- how max long should be output string -// returns 0 if string was not properly decoded -int DecodeBase64(char *Src, char *Dst, int DstLen); - -//Converts string to unicode from string with specified codepage -// stream- input string -// cp- codepage of input string -// out- pointer to new allocated memory that contains unicode string -int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out); - -//Converts string from MIME header to unicode -// stream- input string -// cp- codepage of input string -// storeto- pointer to memory that contains unicode string -// mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' from start and end of string) -void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode); - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -int GetCharsetFromString(char *input, size_t size) -//"ISO-8859-1" to ID from table -{ - char *pin = input; - char *pout, *parser; - - if ((size < 1) || (parser = pout = new char[size + 1]) == nullptr) - return -1; - while ((*pin != 0) && (pin - input < (INT_PTR)size)) { - if ((*pin >= 'a') && (*pin <= 'z')) - *parser++ = *(pin++) - ('a' - 'A'); // make it capital - //else if (*pin=='\"') // this is already done in ExtractFromContentType - // *pin++; //skip the quotes if any - else - *parser++ = *pin++; - } - - *parser = 0; - - #ifdef DEBUG_DECODECODEPAGE - DebugLog(DecodeFile, "%s", pout); - #endif - for (int i = 0; i < CPLENALL; i++) { - size_t len = mir_strlen(CodePageNamesAll[i].NameBase); - if (0 == strncmp(pout, CodePageNamesAll[i].NameBase, len)) { - if (0 == mir_strcmp(pout + len, CodePageNamesAll[i].NameSub)) { - delete[] pout; - return CodePageNamesAll[i].CP; - } - } - } - delete[] pout; - return -1; //not found -} - -int FromHexa(char HexValue, char *DecValue) -{ - if (HexValue >= '0' && HexValue <= '9') { - *DecValue = HexValue - '0'; - return 1; - } - if (HexValue >= 'A' && HexValue <= 'F') { - *DecValue = HexValue - 'A' + 10; - return 1; - } - if (HexValue >= 'a' && HexValue <= 'f') { - *DecValue = HexValue - 'a' + 10; - return 1; - } - return 0; -} - -int FromBase64(char Base64Value, char *DecValue) -{ - if (Base64Value >= 'A' && Base64Value <= 'Z') { - *DecValue = Base64Value - 'A'; - return 1; - } - if (Base64Value >= 'a' && Base64Value <= 'z') { - *DecValue = Base64Value - 'a' + 26; - return 1; - } - if (Base64Value >= '0' && Base64Value <= '9') { - *DecValue = Base64Value - '0' + 52; - return 1; - } - if (Base64Value == '+') { - *DecValue = Base64Value - '+' + 62; - return 1; - } - if (Base64Value == '/') { - *DecValue = Base64Value - '/' + 63; - return 1; - } - if (Base64Value == '=') { - *DecValue = 0; - return 1; - } - return 0; -} - -int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ) -{ - #ifdef DEBUG_DECODEQUOTED - char *DstTemp = Dst; - DebugLog(DecodeFile, "%s", Src); - #endif - for (int Counter = 0; (*Src != 0) && DstLen && (Counter++ < DstLen); Src++, Dst++) - if (*Src == '=') { - if (!isQ) { - if (Src[1] == 0x0D) { - Src++; Src++; - if (Src[0] == 0x0A) Src++; - goto CopyCharQuotedPrintable; - } - if (Src[1] == 0x0A) { - Src++; Src++; - goto CopyCharQuotedPrintable; - } - } - char First, Second; - if (!FromHexa(*(++Src), &First)) { - *Dst++ = '='; Src--; - continue; - } - if (!FromHexa(*(++Src), &Second)) { - *Dst++ = '='; Src--; Src--; - continue; - } - *Dst = (char)(First) << 4; - *Dst += Second; - } - else if (isQ && *Src == '_') - *Dst = ' '; - else - CopyCharQuotedPrintable: // Yeah. Bad programming stile. - *Dst = *Src; - *Dst = 0; - #ifdef DEBUG_DECODEQUOTED - DebugLog(DecodeFile, "%s", DstTemp); - #endif - return 1; -} - -int DecodeBase64(char *Src, char *Dst, int DstLen) -{ - int Result = 0; - char Locator = 0, MiniResult[4]; - char *End = Dst + DstLen; - - MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0; - - #ifdef DEBUG_DECODEBASE64 - char *DstTemp = Dst; - DebugLog(DecodeFile, "\n%s\n\n", Src); - #endif - while (*Src != 0 && DstLen && Dst != End) { - if ((*Src == 0x0D) || (*Src == 0x0A)) { - Src++; - continue; - } - if ((!(Result = FromBase64(*Src, MiniResult + Locator)) && (*Src == 0)) || Locator++ == 3) //end_of_str || end_of_4_bytes - { - Locator = 0; //next write to the first byte - *Dst++ = (char)((MiniResult[0] << 2) | (MiniResult[1] >> 4)); - if (Dst == End) goto end; //DstLen exceeded? - *Dst++ = (char)((MiniResult[1] << 4) | (MiniResult[2] >> 2)); - if (Dst == End) goto end; //someones don't like goto, but not me - *Dst++ = (char)((MiniResult[2] << 6) | MiniResult[3]); - if (!Result && (*Src == 0)) goto end; //end of string? - MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0; //zero 4byte buffer for next loop - } - if (!Result) return 0; //unrecognised character occured - Src++; - } -end: - *Dst = 0; - #ifdef DEBUG_DECODEBASE64 - DebugLog(DecodeFile, "\n%s\n", DstTemp); - #endif - return 1; -} - - - -int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out) -{ - CPINFO CPInfo; - wchar_t *temp, *src = *out, *dest; - size_t outlen; - int streamlen, Index; - - //codepages, which require to have set 0 in dwFlags parameter when calling MultiByteToWideChar - uint32_t CodePagesZeroFlags[] = {50220, 50221, 50222, 50225, 50227, 50229, 52936, 54936, 57002, 57003, 57004, 57005, 57006, 57007, 57008, 57009, 57010, 57011, 65000, 65001}; - - if ((cp != CP_ACP) && (cp != CP_OEMCP) && (cp != CP_MACCP) && (cp != CP_THREAD_ACP) && (cp != CP_SYMBOL) && (cp != CP_UTF7) && (cp != CP_UTF8) && !GetCPInfo(cp, &CPInfo)) - cp = CP_ACP; - #ifdef DEBUG_DECODECODEPAGE - DebugLog(DecodeFile, "%d", cp); - #endif - - for (Index = 0; Index < sizeof(CodePagesZeroFlags) / sizeof(CodePagesZeroFlags[0]); Index++) - if (CodePagesZeroFlags[Index] == cp) { - Index = -1; - break; - } - if (Index == -1) - streamlen = MultiByteToWideChar(cp, 0, stream, -1, nullptr, 0); - else - streamlen = MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, nullptr, 0); - - if (*out != nullptr) - outlen = mir_wstrlen(*out); - else - outlen = 0; - temp = new wchar_t[streamlen + outlen + 1]; - - if (*out != nullptr) { - for (dest = temp; *src != (wchar_t)0; src++, dest++) //copy old string from *out to temp - *dest = *src; - // *dest++=L' '; //add space? - delete[] * out; - } - else - dest = temp; - *out = temp; - - if (Index == -1) { - if (!MultiByteToWideChar(cp, 0, stream, -1, dest, streamlen)) - return 0; - } - else { - if (!MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, dest, streamlen)) - return 0; - } - return 1; -} - -void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode) -{ - char *start = stream, *finder, *finderend; - char Encoding = 0; - - if (stream == nullptr) - return; - - while (WS(start)) start++; - wchar_t *tempstore = nullptr; - if (!ConvertStringToUnicode(stream, cp, &tempstore))return; - - size_t tempstoreLength = mir_wstrlen(tempstore); - - size_t outind = 0; - while (*start != 0) { - if (CODES(start)) { - finder = start + 2; finderend = finder; - while (!CODED(finderend) && !EOS(finderend)) finderend++; - start = finderend; - if (CODED(finderend)) { - Encoding = *(finderend + 1); - switch (Encoding) { - case 'b': - case 'B': - case 'q': - case 'Q': - break; - default: - goto NotEncoded; - } - if (-1 == (cp = (uint32_t)GetCharsetFromString(finder, finderend - finder))) - cp = CP_ACP; - if (Encoding != 0) { - int size = 0, codeend; - char *pcodeend = nullptr; - - finder = finderend + 2; - if (CODED(finder)) - finder++; - while (WS(finder)) finder++; - finderend = finder; - while (!CODEE(finderend) && !EOS(finderend)) finderend++; - if (codeend = CODEE(finderend)) - pcodeend = finderend; - while (WS(finderend - 1)) finderend--; - if ((mode == MIME_MAIL) && (((*finder == '"') && (*(finderend - 1) == '"')))) { - finder++; - finderend--; - } - char *oneWordEncoded = new char[finderend - finder + 1]; - strncpy(oneWordEncoded, finder, finderend - finder); - oneWordEncoded[finderend - finder] = 0; - switch (Encoding) { - case 'b': - case 'B': - size = (finderend - finder) * 3 / 4 + 3 + 1 + 1; - break; - case 'q': - case 'Q': - size = finderend - finder + 1 + 1; - break; - } - - char *DecodedResult = new char[size + 1]; - switch (Encoding) { - case 'q': - case 'Q': - DecodeQuotedPrintable(oneWordEncoded, DecodedResult, size, TRUE); - break; - case 'b': - case 'B': - DecodeBase64(oneWordEncoded, DecodedResult, size); - break; - } - delete[] oneWordEncoded; - if (codeend) - finderend = pcodeend + 2; - if (WS(finderend)) //if string continues and there's some whitespace, add space to string that is to be converted - { - size_t len = mir_strlen(DecodedResult); - DecodedResult[len] = ' '; - DecodedResult[len + 1] = 0; - finderend++; - } - wchar_t *oneWord = nullptr; - if (ConvertStringToUnicode(DecodedResult, cp, &oneWord)) { - size_t len = mir_wstrlen(oneWord); - memcpy(&tempstore[outind], oneWord, len * sizeof(wchar_t)); - outind += len; - } - delete oneWord; - oneWord = nullptr; - delete[] DecodedResult; - start = finderend; - } - else if (!EOS(start)) start++; - } - else if (!EOS(start)) start++; - } - else { -NotEncoded: - tempstore[outind] = tempstore[start - stream]; - outind++; - if (outind > tempstoreLength) break; - start++; - } - } - tempstore[outind] = 0; - *storeto = tempstore; -} +/* + * This code implements decoding encoded MIME header in style + * =?iso-8859-2?Q? "User using email in central Europe characters such as =E9" ?= + * + * (c) majvan 2002-2004 + */ +#include "../stdafx.h" +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +struct _tcptable CodePageNamesAll[]= +{ + { "ANSI", "",TRUE,CP_ACP}, + { "WINDOWS-1", "250",0,1250}, + { "WINDOWS-1", "251",0,1251}, + { "WINDOWS-1", "252",0,1252}, + { "WINDOWS-1", "253",0,1253}, + { "WINDOWS-1", "254",0,1254}, + { "WINDOWS-1", "255",0,1255}, + { "WINDOWS-1", "256",0,1256}, + { "WINDOWS-1", "257",0,1257}, + { "WINDOWS-1", "258",0,1258}, + { "CP1", "250",0,1250}, + { "CP1", "251",0,1251}, + { "CP1", "252",0,1252}, + { "CP1", "253",0,1253}, + { "CP1", "254",0,1254}, + { "CP1", "255",0,1255}, + { "CP1", "256",0,1256}, + { "CP1", "257",0,1257}, + { "CP1", "258",0,1258}, + { "ANSI-1", "250",0,1250}, + { "ANSI-1", "251",0,1251}, + { "ANSI-1", "252",0,1252}, + { "ANSI-1", "253",0,1253}, + { "ANSI-1", "254",0,1254}, + { "ANSI-1", "255",0,1255}, + { "ANSI-1", "256",0,1256}, + { "ANSI-1", "257",0,1257}, + { "ANSI-1", "258",0,1258}, + { "KOI8", "-R",0,20866}, + { "KOI8", "",0,20866}, + { "KOI8", "-U",0,21866}, + { "KOI8", "-RU",0,21866}, + { "US-", "ASCII",0,20127}, + { "CP", "367",0,20127}, + { "ASCII", "",0,20127}, + { "ASCII", "7",0,20127}, + { "ISO-8859", "-1",0,28591}, + { "ISO-8859", "-2",0,28592}, + { "ISO-8859", "-3",0,28593}, + { "ISO-8859", "-4",0,28594}, + { "ISO-8859", "-5",0,28595}, + { "ISO-8859", "-6",0,28596}, + { "ISO-8859", "-7",0,28597}, + { "ISO-8859", "-8",0,28598}, + { "ISO-8859", "-9",0,28599}, + { "ISO-8859", "-15",0,28605}, + { "ISO_8859", "-1",0,28591}, + { "ISO_8859", "-2",0,28592}, + { "ISO_8859", "-3",0,28593}, + { "ISO_8859", "-4",0,28594}, + { "ISO_8859", "-5",0,28595}, + { "ISO_8859", "-6",0,28596}, + { "ISO_8859", "-7",0,28597}, + { "ISO_8859", "-8",0,28598}, + { "ISO_8859", "-9",0,28599}, + { "ISO_8859", "-15",0,28605}, + { "ISO-", "10646-USC2",0,1200}, + { "ISO-2022", "/2-JP",0,50220}, + { "ISO-2022", "-JP",0,50221}, + { "ISO-2022", "/JIS-JP",0,50222}, + { "ISO-2022", "-KR",0,50225}, + { "ISO-2022", "-CH(SP)",0,50227}, + { "ISO-2022", "-CH(TR)",0,50229}, + { "UTF-", "7",0,65000}, + { "UTF-", "8",0,65001}, + { "ARAB-", "TRANSPARENT",0,710}, + { "ASMO-", "TRANSPARENT",0,720}, + { "ASMO-", "449",0,709}, + { "ASMO-", "708",0,708}, + { "BIG5", "",0,950}, + { "EUC-", "CH(SP)",0,51936}, + { "EUC-", "CH(TR)",0,51950}, + { "EUC-", "JP",0,51932}, + { "EUC-", "KR",0,51949}, + { "GB-", "2312",0,20936}, + { "GB", "2312",0,20936}, + { "HZGB-", "2312",0,52936}, + { "IBM-", "037",0,37}, + { "IBM-", "290",0,290}, + { "IBM-", "437",0,437}, + { "IBM-", "500",0,500}, + { "IBM-", "775",0,775}, + { "IBM-", "850",0,850}, + { "IBM-", "852",0,852}, + { "IBM-", "855",0,855}, + { "IBM-", "857",0,857}, + { "IBM-", "860",0,860}, + { "IBM-", "861",0,861}, + { "IBM-", "862",0,862}, + { "IBM-", "863",0,863}, + { "IBM-", "864",0,864}, + { "IBM-", "865",0,865}, + { "IBM-", "866",0,866}, + { "IBM-", "869",0,869}, + { "IBM-", "870",0,870}, + { "IBM-", "875",0,875}, + { "IBM-", "1026",0,1026}, + { "IBM-", "273",0,20273}, + { "IBM-", "277",0,20277}, + { "IBM-", "278",0,20278}, + { "IBM-", "280",0,20280}, + { "IBM-", "284",0,20284}, + { "IBM-", "285",0,20285}, + { "IBM-", "290",0,20290}, + { "IBM-", "297",0,20297}, + { "IBM-", "420",0,20420}, + { "IBM-", "423",0,20423}, + { "IBM-", "871",0,20871}, + { "IBM-", "880",0,20880}, + { "IBM-", "905",0,20905}, + { "IBM-", "THAI",0,20838}, + { "ISCII-", "DEVANAGARI",0,57002}, + { "ISCII-", "BENGALI",0,57003}, + { "ISCII-", "TAMIL",0,57004}, + { "ISCII-", "TELUGU",0,57005}, + { "ISCII-", "ASSAMESE",0,57006}, + { "ISCII-", "ORIYA",0,57007}, + { "ISCII-", "KANNADA",0,57008}, + { "ISCII-", "MALAYALAM",0,57009}, + { "ISCII-", "GUJARATI",0,57010}, + { "ISCII-", "PUNJABI",0,57011}, + { "KOR-", "JOHAB",0,1361}, + { "KSC-", "5601",0,1361}, + { "MAC-", "ROMAN",0,10000}, + { "MAC-", "JP",0,10001}, + { "MAC-", "CH(SP)(BIG5)",0,10002}, + { "MAC-", "KR",0,10003}, + { "MAC-", "AR",0,10004}, + { "MAC-", "HW",0,10005}, + { "MAC-", "GR",0,10006}, + { "MAC-", "CY",0,10007}, + { "MAC-", "CH(SP)(GB2312)",0,10008}, + { "MAC-", "ROMANIA",0,10010}, + { "MAC-", "UA",0,10017}, + { "MAC-", "TH",0,10021}, + { "MAC-", "LAT2",0,10029}, + { "MAC-", "ICE",0,10079}, + { "MAC-", "TR",0,10081}, + { "MAC-", "CR",0,10082} +}; + +int CPLENALL = _countof(CodePageNamesAll); +struct _tcptable *CodePageNamesSupp; +int CPLENSUPP = 1; + +//Gets codepage ID from string representing charset such as "iso-8859-1" +// input- the string +// size- max length of input string +int GetCharsetFromString(char *input, size_t size); + +//HexValue to DecValue ('a' to 10) +// HexValue- hexa value ('a') +// DecValue- poiner where to store dec value +// returns 0 if not success +int FromHexa(char HexValue, char *DecValue); + +//Decodes a char from Base64 +// Base64Value- input char in Base64 +// DecValue- pointer where to store the result +// returns 0 if not success +int FromBase64(char Base64Value, char *DecValue); + +//Decodes string in quoted printable +// Src- input string +// Dst- where to store output string +// DstLen- how max long should be output string +// isQ- if is "Q-encoding" modification. should be TRUE in headers +// always returns 1 +int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ); + +//Decodes string in base64 +// Src- input string +// Dst- where to store output string +// DstLen- how max long should be output string +// returns 0 if string was not properly decoded +int DecodeBase64(char *Src, char *Dst, int DstLen); + +//Converts string to unicode from string with specified codepage +// stream- input string +// cp- codepage of input string +// out- pointer to new allocated memory that contains unicode string +int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out); + +//Converts string from MIME header to unicode +// stream- input string +// cp- codepage of input string +// storeto- pointer to memory that contains unicode string +// mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' from start and end of string) +void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode); + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +int GetCharsetFromString(char *input, size_t size) +//"ISO-8859-1" to ID from table +{ + char *pin = input; + char *pout, *parser; + + if ((size < 1) || (parser = pout = new char[size + 1]) == nullptr) + return -1; + while ((*pin != 0) && (pin - input < (INT_PTR)size)) { + if ((*pin >= 'a') && (*pin <= 'z')) + *parser++ = *(pin++) - ('a' - 'A'); // make it capital + //else if (*pin=='\"') // this is already done in ExtractFromContentType + // *pin++; //skip the quotes if any + else + *parser++ = *pin++; + } + + *parser = 0; + + #ifdef DEBUG_DECODECODEPAGE + DebugLog(DecodeFile, "%s", pout); + #endif + for (int i = 0; i < CPLENALL; i++) { + size_t len = mir_strlen(CodePageNamesAll[i].NameBase); + if (0 == strncmp(pout, CodePageNamesAll[i].NameBase, len)) { + if (0 == mir_strcmp(pout + len, CodePageNamesAll[i].NameSub)) { + delete[] pout; + return CodePageNamesAll[i].CP; + } + } + } + delete[] pout; + return -1; //not found +} + +int FromHexa(char HexValue, char *DecValue) +{ + if (HexValue >= '0' && HexValue <= '9') { + *DecValue = HexValue - '0'; + return 1; + } + if (HexValue >= 'A' && HexValue <= 'F') { + *DecValue = HexValue - 'A' + 10; + return 1; + } + if (HexValue >= 'a' && HexValue <= 'f') { + *DecValue = HexValue - 'a' + 10; + return 1; + } + return 0; +} + +int FromBase64(char Base64Value, char *DecValue) +{ + if (Base64Value >= 'A' && Base64Value <= 'Z') { + *DecValue = Base64Value - 'A'; + return 1; + } + if (Base64Value >= 'a' && Base64Value <= 'z') { + *DecValue = Base64Value - 'a' + 26; + return 1; + } + if (Base64Value >= '0' && Base64Value <= '9') { + *DecValue = Base64Value - '0' + 52; + return 1; + } + if (Base64Value == '+') { + *DecValue = Base64Value - '+' + 62; + return 1; + } + if (Base64Value == '/') { + *DecValue = Base64Value - '/' + 63; + return 1; + } + if (Base64Value == '=') { + *DecValue = 0; + return 1; + } + return 0; +} + +int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ) +{ + #ifdef DEBUG_DECODEQUOTED + char *DstTemp = Dst; + DebugLog(DecodeFile, "%s", Src); + #endif + for (int Counter = 0; (*Src != 0) && DstLen && (Counter++ < DstLen); Src++, Dst++) + if (*Src == '=') { + if (!isQ) { + if (Src[1] == 0x0D) { + Src++; Src++; + if (Src[0] == 0x0A) Src++; + goto CopyCharQuotedPrintable; + } + if (Src[1] == 0x0A) { + Src++; Src++; + goto CopyCharQuotedPrintable; + } + } + char First, Second; + if (!FromHexa(*(++Src), &First)) { + *Dst++ = '='; Src--; + continue; + } + if (!FromHexa(*(++Src), &Second)) { + *Dst++ = '='; Src--; Src--; + continue; + } + *Dst = (char)(First) << 4; + *Dst += Second; + } + else if (isQ && *Src == '_') + *Dst = ' '; + else + CopyCharQuotedPrintable: // Yeah. Bad programming stile. + *Dst = *Src; + *Dst = 0; + #ifdef DEBUG_DECODEQUOTED + DebugLog(DecodeFile, "%s", DstTemp); + #endif + return 1; +} + +int DecodeBase64(char *Src, char *Dst, int DstLen) +{ + int Result = 0; + char Locator = 0, MiniResult[4]; + char *End = Dst + DstLen; + + MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0; + + #ifdef DEBUG_DECODEBASE64 + char *DstTemp = Dst; + DebugLog(DecodeFile, "\n%s\n\n", Src); + #endif + while (*Src != 0 && DstLen && Dst != End) { + if ((*Src == 0x0D) || (*Src == 0x0A)) { + Src++; + continue; + } + if ((!(Result = FromBase64(*Src, MiniResult + Locator)) && (*Src == 0)) || Locator++ == 3) //end_of_str || end_of_4_bytes + { + Locator = 0; //next write to the first byte + *Dst++ = (char)((MiniResult[0] << 2) | (MiniResult[1] >> 4)); + if (Dst == End) goto end; //DstLen exceeded? + *Dst++ = (char)((MiniResult[1] << 4) | (MiniResult[2] >> 2)); + if (Dst == End) goto end; //someones don't like goto, but not me + *Dst++ = (char)((MiniResult[2] << 6) | MiniResult[3]); + if (!Result && (*Src == 0)) goto end; //end of string? + MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0; //zero 4byte buffer for next loop + } + if (!Result) return 0; //unrecognised character occured + Src++; + } +end: + *Dst = 0; + #ifdef DEBUG_DECODEBASE64 + DebugLog(DecodeFile, "\n%s\n", DstTemp); + #endif + return 1; +} + + + +int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out) +{ + CPINFO CPInfo; + wchar_t *temp, *src = *out, *dest; + size_t outlen; + int streamlen, Index; + + //codepages, which require to have set 0 in dwFlags parameter when calling MultiByteToWideChar + uint32_t CodePagesZeroFlags[] = {50220, 50221, 50222, 50225, 50227, 50229, 52936, 54936, 57002, 57003, 57004, 57005, 57006, 57007, 57008, 57009, 57010, 57011, 65000, 65001}; + + if ((cp != CP_ACP) && (cp != CP_OEMCP) && (cp != CP_MACCP) && (cp != CP_THREAD_ACP) && (cp != CP_SYMBOL) && (cp != CP_UTF7) && (cp != CP_UTF8) && !GetCPInfo(cp, &CPInfo)) + cp = CP_ACP; + #ifdef DEBUG_DECODECODEPAGE + DebugLog(DecodeFile, "%d", cp); + #endif + + for (Index = 0; Index < sizeof(CodePagesZeroFlags) / sizeof(CodePagesZeroFlags[0]); Index++) + if (CodePagesZeroFlags[Index] == cp) { + Index = -1; + break; + } + if (Index == -1) + streamlen = MultiByteToWideChar(cp, 0, stream, -1, nullptr, 0); + else + streamlen = MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, nullptr, 0); + + if (*out != nullptr) + outlen = mir_wstrlen(*out); + else + outlen = 0; + temp = new wchar_t[streamlen + outlen + 1]; + + if (*out != nullptr) { + for (dest = temp; *src != (wchar_t)0; src++, dest++) //copy old string from *out to temp + *dest = *src; + // *dest++=L' '; //add space? + delete[] * out; + } + else + dest = temp; + *out = temp; + + if (Index == -1) { + if (!MultiByteToWideChar(cp, 0, stream, -1, dest, streamlen)) + return 0; + } + else { + if (!MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, dest, streamlen)) + return 0; + } + return 1; +} + +void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode) +{ + char *start = stream, *finder, *finderend; + char Encoding = 0; + + if (stream == nullptr) + return; + + while (WS(start)) start++; + wchar_t *tempstore = nullptr; + if (!ConvertStringToUnicode(stream, cp, &tempstore))return; + + size_t tempstoreLength = mir_wstrlen(tempstore); + + size_t outind = 0; + while (*start != 0) { + if (CODES(start)) { + finder = start + 2; finderend = finder; + while (!CODED(finderend) && !EOS(finderend)) finderend++; + start = finderend; + if (CODED(finderend)) { + Encoding = *(finderend + 1); + switch (Encoding) { + case 'b': + case 'B': + case 'q': + case 'Q': + break; + default: + goto NotEncoded; + } + if (-1 == (cp = (uint32_t)GetCharsetFromString(finder, finderend - finder))) + cp = CP_ACP; + if (Encoding != 0) { + int size = 0, codeend; + char *pcodeend = nullptr; + + finder = finderend + 2; + if (CODED(finder)) + finder++; + while (WS(finder)) finder++; + finderend = finder; + while (!CODEE(finderend) && !EOS(finderend)) finderend++; + if (codeend = CODEE(finderend)) + pcodeend = finderend; + while (WS(finderend - 1)) finderend--; + if ((mode == MIME_MAIL) && (((*finder == '"') && (*(finderend - 1) == '"')))) { + finder++; + finderend--; + } + char *oneWordEncoded = new char[finderend - finder + 1]; + strncpy(oneWordEncoded, finder, finderend - finder); + oneWordEncoded[finderend - finder] = 0; + switch (Encoding) { + case 'b': + case 'B': + size = (finderend - finder) * 3 / 4 + 3 + 1 + 1; + break; + case 'q': + case 'Q': + size = finderend - finder + 1 + 1; + break; + } + + char *DecodedResult = new char[size + 1]; + switch (Encoding) { + case 'q': + case 'Q': + DecodeQuotedPrintable(oneWordEncoded, DecodedResult, size, TRUE); + break; + case 'b': + case 'B': + DecodeBase64(oneWordEncoded, DecodedResult, size); + break; + } + delete[] oneWordEncoded; + if (codeend) + finderend = pcodeend + 2; + if (WS(finderend)) //if string continues and there's some whitespace, add space to string that is to be converted + { + size_t len = mir_strlen(DecodedResult); + DecodedResult[len] = ' '; + DecodedResult[len + 1] = 0; + finderend++; + } + wchar_t *oneWord = nullptr; + if (ConvertStringToUnicode(DecodedResult, cp, &oneWord)) { + size_t len = mir_wstrlen(oneWord); + memcpy(&tempstore[outind], oneWord, len * sizeof(wchar_t)); + outind += len; + } + delete oneWord; + oneWord = nullptr; + delete[] DecodedResult; + start = finderend; + } + else if (!EOS(start)) start++; + } + else if (!EOS(start)) start++; + } + else { +NotEncoded: + tempstore[outind] = tempstore[start - stream]; + outind++; + if (outind > tempstoreLength) break; + start++; + } + } + tempstore[outind] = 0; + *storeto = tempstore; +} diff --git a/protocols/YAMN/src/mails/mails.cpp b/protocols/YAMN/src/mails/mails.cpp index 168c6c9397..1385cb649d 100644 --- a/protocols/YAMN/src/mails/mails.cpp +++ b/protocols/YAMN/src/mails/mails.cpp @@ -1,473 +1,473 @@ -/* - * This code implements retrieving info from MIME header - * - * (c) majvan 2002-2004 - */ - -#include "../stdafx.h" - - //-------------------------------------------------------------------------------------------------- - //-------------------------------------------------------------------------------------------------- - - // SMALL INTRO - // Mails are queued in a queue (chained list). Pointer to first mail is pointed from Account structure - // member called Mails. - // Mail queue is ended with NULL- pointered mail (NULL handle) - - //Creates new mail for plugin (calling plugin's constructor, when plugin imported to YAMN) -INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam); - -//Deletes mail for plugin (calling plugin's destructor, when plugin imported to YAMN) -INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam); - -//Loads mail data from standard storage to memory -INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam); - -//Deletes mail data from memory -INT_PTR UnloadMailDataSvc(WPARAM wParam, LPARAM); - -//Saves mail data from memory to standard storage -INT_PTR SaveMailDataSvc(WPARAM wParam, LPARAM lParam); - -//Appends second MIME mail queue to the first one -//Only finds the end of first queue and its Next memember repoints to second one -void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second); - -//Synchronizes two accounts -//Function finds, if there were some mails deleted from mailbox and deletes (depends on RemovedOld param) them from OldQueue -//Next finds, if there are new mails. Mails that are still on mailbox are deleted (depends on RemovedNew param) from NewQueue -//After this, OldQueue is pointer to mails that are on mailbox, but not new mails -//and NewQueue contains new mails in account -//New accounts can be then appended to account mails queue, but they have set the New flag -// -//Two mails equals if they have the same ID -// -// hPlugin- handle of plugin going to delete mails -// OldQueue- queue of mails that we found on mailbox last time, after function finishes queue contains all mails except new ones -// RemovedOld- queue of mails where to store removed mails from OldQueue, if NULL deletes mails from OldQueue -// NewQueue- queue of mails that we found on mailbox (all mails), after function finishes queue contains only new mails -// RemovedNew- queue of mails where to store removed mails from NewQueue, if NULL deletes mails from NewQueue -//So function works like: -//1. delete (or move to RemovedOld queue if RemovedOld is not NULL) all mails from OldQueue not found in NewQueue -//2. delete (or move to RemovedNew queue if RemovedNew is not NULL) all mails from NewQueue found in OldQueue -void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew); - -//Deletes messages from mail From to the end -// Account- account who owns mails -// From- first mail in queue, which is going to delete -void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From); - -//Removes message from queue, does not delete from memory -// From- queue pointer -// Which- mail to delete -// mode- nonzero if you want to decrement numbers in messages that are bigger than the one in Which mail, 0 if not -void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode); - -//Finds message in queue that has the same ID number -// From- message queue -// ID- pointer to ID -// returns pointer to found message, NULL if not found -HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID); - -//Translate header from text to queue of CMimeItem structures -//This means that new queue will contain all info about headers -// stream- pointer to text containing header (can be ended with zero) -// len- length of stream -// head- function fills this pointer to first header item in queue -void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head); - -//Creates new mail queue, copying only these mails, that have set flag for deleting -// From- message queue, whose mail with given flag are duplicated -// returns new mail queue (or NULL when no mail with flag is in From queue) -//Function does not copy the whole mails, it copies only ID string. And ID is copied as string, so -//you can use this fcn only if you have your ID as pointer to char string ended with zero character -HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From); - -//Sets/removes flags from specific mails -// From- pointer to first message -// FlagsSet- mail must have set these flags... -// FlagsNotSet- ...and must not have set these flags... -// FlagsToSetRemove- ...to set/remove these flags (see mode) -// mode- nonzero to set, else remove -void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode); - -struct CExportedFunctions MailExportedFcn[] = -{ - {YAMN_SYNCHROMIMEMSGSID, (void *)SynchroMessagesFcn}, - {YAMN_TRANSLATEHEADERID, (void *)TranslateHeaderFcn}, - {YAMN_APPENDQUEUEID, (void *)AppendQueueFcn}, - {YAMN_DELETEMIMEQUEUEID, (void *)DeleteMessagesToEndFcn}, - {YAMN_DELETEMIMEMESSAGEID, (void *)DeleteMessageFromQueueFcn}, - {YAMN_FINDMIMEMESSAGEID, (void *)FindMessageByIDFcn}, - {YAMN_CREATENEWDELETEQUEUEID, (void *)CreateNewDeleteQueueFcn}, - {YAMN_SETREMOVEQUEUEFLAGSID, (void *)SetRemoveFlagsInQueueFcn}, -}; - -struct CExportedServices MailExportedSvc[] = -{ - {MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc}, - {MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc}, - {MS_YAMN_LOADMAILDATA, LoadMailDataSvc}, - {MS_YAMN_UNLOADMAILDATA, UnloadMailDataSvc}, - {MS_YAMN_SAVEMAILDATA, SaveMailDataSvc}, -}; - - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam) -{ - CAccount *Account = (CAccount *)wParam; - uint32_t MailVersion = (uint32_t)lParam; - HYAMNMAIL NewMail; - - //test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match) - if (MailVersion != YAMN_MAILVERSION) - return NULL; - - if (Account->Plugin != nullptr) { - if (Account->Plugin->MailFcn->NewMailFcnPtr != nullptr) { - //Let plugin create its own structure, which can be derived from CAccount structure - if (nullptr == (NewMail = Account->Plugin->MailFcn->NewMailFcnPtr(Account, YAMN_MAILVERSION))) - return NULL; - } - else { - //We suggest plugin uses standard CAccount structure, so we create it - if (nullptr == (NewMail = new YAMNMAIL)) - //If not created successfully - return NULL; - NewMail->MailData = nullptr; - } - //Init every members of structure, used by YAMN - return (INT_PTR)NewMail; - } - return NULL; -} - -INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam) -{ - HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; - HYAMNMAIL OldMail = (HYAMNMAIL)lParam; - struct CMimeItem *TH; - - if (Plugin->MailFcn != nullptr) { - if (Plugin->MailFcn->DeleteMailFcnPtr != nullptr) { - //Let plugin delete its own CMimeMsgQueue derived structure - Plugin->MailFcn->DeleteMailFcnPtr(OldMail); - return 1; - } - } - if (OldMail->MailData != nullptr) { - if (OldMail->MailData->Body != nullptr) - delete[] OldMail->MailData->Body; - if ((TH = OldMail->MailData->TranslatedHeader) != nullptr) - for (; OldMail->MailData->TranslatedHeader != nullptr;) { - TH = TH->Next; - if (OldMail->MailData->TranslatedHeader->name != nullptr) - delete[] OldMail->MailData->TranslatedHeader->name; - if (OldMail->MailData->TranslatedHeader->value != nullptr) - delete[] OldMail->MailData->TranslatedHeader->value; - delete OldMail->MailData->TranslatedHeader; - OldMail->MailData->TranslatedHeader = TH; - } - delete OldMail->MailData; - } - if (OldMail->ID != nullptr) - delete[] OldMail->ID; - - delete OldMail; //consider mail as standard HYAMNMAIL, not initialized before and use its own destructor - return 1; -} - - -void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second) -{ - HYAMNMAIL Finder = first; - while (Finder->Next != nullptr) Finder = Finder->Next; - Finder->Next = second; -} - -INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam) -{ - HYAMNMAIL Mail = (HYAMNMAIL)wParam; - uint32_t MailVersion = (uint32_t)lParam; - - if (MailVersion != YAMN_MAILDATAVERSION) - return NULL; - - // now we have all data to memory persisting, so no loading is needed - return (INT_PTR)Mail->MailData; -} - -INT_PTR UnloadMailDataSvc(WPARAM, LPARAM) -{ - return 1; -} - -INT_PTR SaveMailDataSvc(WPARAM, LPARAM lParam) -{ - uint32_t MailVersion = (uint32_t)lParam; - - if (MailVersion != YAMN_MAILDATAVERSION) - return (INT_PTR)-1; - - // now we have all data to memory persisting, so no saving is needed - return (INT_PTR)0; -} - -void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew) -//deletes messages from new queue, if they are old -//it also deletes messages from old queue, if they are not in mailbox anymore -//"YAMN_MSG_DELETED" messages in old queue remain in old queue (are never removed, although they are not in new queue) -//"YAMN_MSG_DELETED" messages in new queue remain in new queue (are never removed, although they can be in old queue) -{ - HYAMNMAIL Finder, FinderPrev; - HYAMNMAIL Parser, ParserPrev; - HYAMNMAIL RemovedOldParser = nullptr; - HYAMNMAIL RemovedNewParser = nullptr; - if (RemovedOld != nullptr) *RemovedOld = nullptr; - if (RemovedNew != nullptr) *RemovedNew = nullptr; - - for (FinderPrev = nullptr, Finder = *OldQueue; Finder != nullptr;) { - if (Finder->Flags & YAMN_MSG_DELETED) //if old queue contains deleted mail - { - FinderPrev = Finder; - Finder = Finder->Next; //get next message in old queue for testing - continue; - } - for (ParserPrev = nullptr, Parser = *NewQueue; Parser != nullptr; ParserPrev = Parser, Parser = Parser->Next) { - if (Parser->Flags & YAMN_MSG_DELETED) - continue; - - if (Parser->ID == nullptr) //simply ignore the message, that has not filled its ID - continue; - - if (0 == mir_strcmp(Parser->ID, Finder->ID)) //search for equal message in new queue - break; - } - if (Parser != nullptr) //found equal message in new queue - { - if (Parser == *NewQueue) - *NewQueue = (*NewQueue)->Next; - else - ParserPrev->Next = Parser->Next; - Finder->Number = Parser->Number; //rewrite the number of current message in old queue - - if (RemovedNew == nullptr) //delete from new queue - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Parser); - else //or move to RemovedNew - { - if (RemovedNewParser == nullptr) //if it is first mail removed from NewQueue - *RemovedNew = Parser; //set RemovedNew queue to point to first message in removed queue - else - RemovedNewParser->Next = Parser; //else don't forget to show to next message in RemovedNew queue - RemovedNewParser = Parser; //follow RemovedNew queue - RemovedNewParser->Next = nullptr; - } - FinderPrev = Finder; - Finder = Finder->Next; //get next message in old queue for testing - } - else //a message was already deleted from mailbox - { - if (Finder == *OldQueue) //if we are at the first item in OldQueue - { - *OldQueue = (*OldQueue)->Next; //set OldQueue to next item - if (RemovedOld == nullptr) //delete from old queue - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder); - else //or move to RemovedOld - { - if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue - *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue - else - RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue - RemovedOldParser = Finder; //follow RemovedOld queue - RemovedOldParser->Next = nullptr; - } - Finder = *OldQueue; - } - else { - FinderPrev->Next = Finder->Next; - if (RemovedOld == nullptr) //delete from old queue - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder); - else //or move to RemovedOld - { - if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue - *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue - else - RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue - RemovedOldParser = Finder; //follow RemovedOld queue - RemovedOldParser->Next = nullptr; - } - Finder = FinderPrev->Next; - } - } - } -} - -void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From) -{ - HYAMNMAIL Temp; - while (From != nullptr) { - Temp = From; - From = From->Next; - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Temp); - } -} - -void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0) -{ - uint32_t Number = Which->Number; - HYAMNMAIL Parser; - - if (*From == Which) { - Parser = Which->Next; - *From = Parser; - } - else { - for (Parser = *From; Which != Parser->Next; Parser = Parser->Next) - if (mode && (Parser->Number > Number)) Parser->Number--; - if (mode && (Parser->Number > Number)) Parser->Number--; - Parser->Next = Parser->Next->Next; - Parser = Which->Next; - } - if (mode) - for (; Parser != nullptr; Parser = Parser->Next) - if (Parser->Number > Number) Parser->Number--; -} - -void DeleteMessagesFromQueue(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0) -{ - HYAMNMAIL Parser; - - for (Parser = Which; Parser != nullptr; Parser = Parser->Next) - DeleteMessageFromQueueFcn(From, Parser, mode); -} - -HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID) -{ - HYAMNMAIL Browser; - - for (Browser = From; Browser != nullptr; Browser = Browser->Next) - if (0 == mir_strcmp(Browser->ID, ID)) - break; - return Browser; -} - -void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head) -{ - try { - char *finder = stream; - char *prev1, *prev2, *prev3; - struct CMimeItem *Item = nullptr; - - while (finder <= (stream + len)) { - while (ENDLINEWS(finder)) finder++; - - //at the start of line - if (DOTLINE(finder + 1)) //at the end of stream - break; - - prev1 = finder; - - while (*finder != ':' && !EOS(finder)) finder++; - if (!EOS(finder)) - prev2 = finder++; - else - break; - - while (WS(finder) && !EOS(finder)) finder++; - if (!EOS(finder)) - prev3 = finder; - else - break; - - do { - if (ENDLINEWS(finder)) finder += 2; //after endline information continues - while (!ENDLINE(finder) && !EOS(finder)) finder++; - } while (ENDLINEWS(finder)); - - if (Item != nullptr) { - if (nullptr == (Item->Next = new struct CMimeItem)) - break; - Item = Item->Next; - } - else { - Item = new CMimeItem; - *head = Item; - } - - Item->Next = nullptr; - Item->name = new char[prev2 - prev1 + 1]; - mir_strncpy(Item->name, prev1, prev2 - prev1 + 1); - Item->value = new char[finder - prev3 + 1]; - mir_strncpy(Item->value, prev3, finder - prev3 + 1); - - if (EOS(finder)) - break; - finder++; - if (ENDLINE(finder)) { - finder++; - if (ENDLINE(finder)) { - // end of headers. message body begins - finder++; - if (ENDLINE(finder))finder++; - prev1 = finder; - while (!DOTLINE(finder + 1))finder++; - if (ENDLINE(finder))finder--; - prev2 = finder; - if (prev2 > prev1) { // yes, we have body - if (nullptr == (Item->Next = new struct CMimeItem)) break; // Cant create new item?! - Item = Item->Next; - Item->Next = nullptr;//just in case; - Item->name = new char[5]; strncpy(Item->name, "Body", 5); - Item->value = new char[prev2 - prev1]; - mir_strncpy(Item->value, prev1, prev2 - prev1 - 1); - } - break; // there is nothing else - } - } - } - } - catch (...) { - MessageBoxA(nullptr, "Translate header error", "", 0); - } -} - -HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From) -{ - HYAMNMAIL FirstMail, Browser = nullptr; - - for (FirstMail = nullptr; From != nullptr; From = From->Next) { - if ((From->Flags & (YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE)) && !(From->Flags & YAMN_MSG_DELETED)) { - if (FirstMail == nullptr) { - FirstMail = Browser = new YAMNMAIL; - if (FirstMail == nullptr) - break; - } - else { - Browser->Next = new YAMNMAIL; - Browser = Browser->Next; - } - Browser->ID = new char[mir_strlen(From->ID) + 1]; - mir_strcpy(Browser->ID, From->ID); - Browser->Number = From->Number; - Browser->Flags = From->Flags; - } - } - return FirstMail; -} - -void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode) -{ - HYAMNMAIL msgq; - - for (msgq = (HYAMNMAIL)From; msgq != nullptr; msgq = msgq->Next) { - if ((FlagsSet == (msgq->Flags & FlagsSet)) && (0 == (msgq->Flags & FlagsNotSet))) { - if (mode) - msgq->Flags = msgq->Flags | FlagsToSetRemove; - else - msgq->Flags = msgq->Flags & ~FlagsToSetRemove; - } - } -} +/* + * This code implements retrieving info from MIME header + * + * (c) majvan 2002-2004 + */ + +#include "../stdafx.h" + + //-------------------------------------------------------------------------------------------------- + //-------------------------------------------------------------------------------------------------- + + // SMALL INTRO + // Mails are queued in a queue (chained list). Pointer to first mail is pointed from Account structure + // member called Mails. + // Mail queue is ended with NULL- pointered mail (NULL handle) + + //Creates new mail for plugin (calling plugin's constructor, when plugin imported to YAMN) +INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam); + +//Deletes mail for plugin (calling plugin's destructor, when plugin imported to YAMN) +INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam); + +//Loads mail data from standard storage to memory +INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam); + +//Deletes mail data from memory +INT_PTR UnloadMailDataSvc(WPARAM wParam, LPARAM); + +//Saves mail data from memory to standard storage +INT_PTR SaveMailDataSvc(WPARAM wParam, LPARAM lParam); + +//Appends second MIME mail queue to the first one +//Only finds the end of first queue and its Next memember repoints to second one +void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second); + +//Synchronizes two accounts +//Function finds, if there were some mails deleted from mailbox and deletes (depends on RemovedOld param) them from OldQueue +//Next finds, if there are new mails. Mails that are still on mailbox are deleted (depends on RemovedNew param) from NewQueue +//After this, OldQueue is pointer to mails that are on mailbox, but not new mails +//and NewQueue contains new mails in account +//New accounts can be then appended to account mails queue, but they have set the New flag +// +//Two mails equals if they have the same ID +// +// hPlugin- handle of plugin going to delete mails +// OldQueue- queue of mails that we found on mailbox last time, after function finishes queue contains all mails except new ones +// RemovedOld- queue of mails where to store removed mails from OldQueue, if NULL deletes mails from OldQueue +// NewQueue- queue of mails that we found on mailbox (all mails), after function finishes queue contains only new mails +// RemovedNew- queue of mails where to store removed mails from NewQueue, if NULL deletes mails from NewQueue +//So function works like: +//1. delete (or move to RemovedOld queue if RemovedOld is not NULL) all mails from OldQueue not found in NewQueue +//2. delete (or move to RemovedNew queue if RemovedNew is not NULL) all mails from NewQueue found in OldQueue +void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew); + +//Deletes messages from mail From to the end +// Account- account who owns mails +// From- first mail in queue, which is going to delete +void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From); + +//Removes message from queue, does not delete from memory +// From- queue pointer +// Which- mail to delete +// mode- nonzero if you want to decrement numbers in messages that are bigger than the one in Which mail, 0 if not +void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode); + +//Finds message in queue that has the same ID number +// From- message queue +// ID- pointer to ID +// returns pointer to found message, NULL if not found +HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID); + +//Translate header from text to queue of CMimeItem structures +//This means that new queue will contain all info about headers +// stream- pointer to text containing header (can be ended with zero) +// len- length of stream +// head- function fills this pointer to first header item in queue +void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head); + +//Creates new mail queue, copying only these mails, that have set flag for deleting +// From- message queue, whose mail with given flag are duplicated +// returns new mail queue (or NULL when no mail with flag is in From queue) +//Function does not copy the whole mails, it copies only ID string. And ID is copied as string, so +//you can use this fcn only if you have your ID as pointer to char string ended with zero character +HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From); + +//Sets/removes flags from specific mails +// From- pointer to first message +// FlagsSet- mail must have set these flags... +// FlagsNotSet- ...and must not have set these flags... +// FlagsToSetRemove- ...to set/remove these flags (see mode) +// mode- nonzero to set, else remove +void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode); + +struct CExportedFunctions MailExportedFcn[] = +{ + {YAMN_SYNCHROMIMEMSGSID, (void *)SynchroMessagesFcn}, + {YAMN_TRANSLATEHEADERID, (void *)TranslateHeaderFcn}, + {YAMN_APPENDQUEUEID, (void *)AppendQueueFcn}, + {YAMN_DELETEMIMEQUEUEID, (void *)DeleteMessagesToEndFcn}, + {YAMN_DELETEMIMEMESSAGEID, (void *)DeleteMessageFromQueueFcn}, + {YAMN_FINDMIMEMESSAGEID, (void *)FindMessageByIDFcn}, + {YAMN_CREATENEWDELETEQUEUEID, (void *)CreateNewDeleteQueueFcn}, + {YAMN_SETREMOVEQUEUEFLAGSID, (void *)SetRemoveFlagsInQueueFcn}, +}; + +struct CExportedServices MailExportedSvc[] = +{ + {MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc}, + {MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc}, + {MS_YAMN_LOADMAILDATA, LoadMailDataSvc}, + {MS_YAMN_UNLOADMAILDATA, UnloadMailDataSvc}, + {MS_YAMN_SAVEMAILDATA, SaveMailDataSvc}, +}; + + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam) +{ + CAccount *Account = (CAccount *)wParam; + uint32_t MailVersion = (uint32_t)lParam; + HYAMNMAIL NewMail; + + //test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match) + if (MailVersion != YAMN_MAILVERSION) + return NULL; + + if (Account->Plugin != nullptr) { + if (Account->Plugin->MailFcn->NewMailFcnPtr != nullptr) { + //Let plugin create its own structure, which can be derived from CAccount structure + if (nullptr == (NewMail = Account->Plugin->MailFcn->NewMailFcnPtr(Account, YAMN_MAILVERSION))) + return NULL; + } + else { + //We suggest plugin uses standard CAccount structure, so we create it + if (nullptr == (NewMail = new YAMNMAIL)) + //If not created successfully + return NULL; + NewMail->MailData = nullptr; + } + //Init every members of structure, used by YAMN + return (INT_PTR)NewMail; + } + return NULL; +} + +INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; + HYAMNMAIL OldMail = (HYAMNMAIL)lParam; + struct CMimeItem *TH; + + if (Plugin->MailFcn != nullptr) { + if (Plugin->MailFcn->DeleteMailFcnPtr != nullptr) { + //Let plugin delete its own CMimeMsgQueue derived structure + Plugin->MailFcn->DeleteMailFcnPtr(OldMail); + return 1; + } + } + if (OldMail->MailData != nullptr) { + if (OldMail->MailData->Body != nullptr) + delete[] OldMail->MailData->Body; + if ((TH = OldMail->MailData->TranslatedHeader) != nullptr) + for (; OldMail->MailData->TranslatedHeader != nullptr;) { + TH = TH->Next; + if (OldMail->MailData->TranslatedHeader->name != nullptr) + delete[] OldMail->MailData->TranslatedHeader->name; + if (OldMail->MailData->TranslatedHeader->value != nullptr) + delete[] OldMail->MailData->TranslatedHeader->value; + delete OldMail->MailData->TranslatedHeader; + OldMail->MailData->TranslatedHeader = TH; + } + delete OldMail->MailData; + } + if (OldMail->ID != nullptr) + delete[] OldMail->ID; + + delete OldMail; //consider mail as standard HYAMNMAIL, not initialized before and use its own destructor + return 1; +} + + +void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second) +{ + HYAMNMAIL Finder = first; + while (Finder->Next != nullptr) Finder = Finder->Next; + Finder->Next = second; +} + +INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam) +{ + HYAMNMAIL Mail = (HYAMNMAIL)wParam; + uint32_t MailVersion = (uint32_t)lParam; + + if (MailVersion != YAMN_MAILDATAVERSION) + return NULL; + + // now we have all data to memory persisting, so no loading is needed + return (INT_PTR)Mail->MailData; +} + +INT_PTR UnloadMailDataSvc(WPARAM, LPARAM) +{ + return 1; +} + +INT_PTR SaveMailDataSvc(WPARAM, LPARAM lParam) +{ + uint32_t MailVersion = (uint32_t)lParam; + + if (MailVersion != YAMN_MAILDATAVERSION) + return (INT_PTR)-1; + + // now we have all data to memory persisting, so no saving is needed + return (INT_PTR)0; +} + +void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew) +//deletes messages from new queue, if they are old +//it also deletes messages from old queue, if they are not in mailbox anymore +//"YAMN_MSG_DELETED" messages in old queue remain in old queue (are never removed, although they are not in new queue) +//"YAMN_MSG_DELETED" messages in new queue remain in new queue (are never removed, although they can be in old queue) +{ + HYAMNMAIL Finder, FinderPrev; + HYAMNMAIL Parser, ParserPrev; + HYAMNMAIL RemovedOldParser = nullptr; + HYAMNMAIL RemovedNewParser = nullptr; + if (RemovedOld != nullptr) *RemovedOld = nullptr; + if (RemovedNew != nullptr) *RemovedNew = nullptr; + + for (FinderPrev = nullptr, Finder = *OldQueue; Finder != nullptr;) { + if (Finder->Flags & YAMN_MSG_DELETED) //if old queue contains deleted mail + { + FinderPrev = Finder; + Finder = Finder->Next; //get next message in old queue for testing + continue; + } + for (ParserPrev = nullptr, Parser = *NewQueue; Parser != nullptr; ParserPrev = Parser, Parser = Parser->Next) { + if (Parser->Flags & YAMN_MSG_DELETED) + continue; + + if (Parser->ID == nullptr) //simply ignore the message, that has not filled its ID + continue; + + if (0 == mir_strcmp(Parser->ID, Finder->ID)) //search for equal message in new queue + break; + } + if (Parser != nullptr) //found equal message in new queue + { + if (Parser == *NewQueue) + *NewQueue = (*NewQueue)->Next; + else + ParserPrev->Next = Parser->Next; + Finder->Number = Parser->Number; //rewrite the number of current message in old queue + + if (RemovedNew == nullptr) //delete from new queue + DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Parser); + else //or move to RemovedNew + { + if (RemovedNewParser == nullptr) //if it is first mail removed from NewQueue + *RemovedNew = Parser; //set RemovedNew queue to point to first message in removed queue + else + RemovedNewParser->Next = Parser; //else don't forget to show to next message in RemovedNew queue + RemovedNewParser = Parser; //follow RemovedNew queue + RemovedNewParser->Next = nullptr; + } + FinderPrev = Finder; + Finder = Finder->Next; //get next message in old queue for testing + } + else //a message was already deleted from mailbox + { + if (Finder == *OldQueue) //if we are at the first item in OldQueue + { + *OldQueue = (*OldQueue)->Next; //set OldQueue to next item + if (RemovedOld == nullptr) //delete from old queue + DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder); + else //or move to RemovedOld + { + if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue + *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue + else + RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue + RemovedOldParser = Finder; //follow RemovedOld queue + RemovedOldParser->Next = nullptr; + } + Finder = *OldQueue; + } + else { + FinderPrev->Next = Finder->Next; + if (RemovedOld == nullptr) //delete from old queue + DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder); + else //or move to RemovedOld + { + if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue + *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue + else + RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue + RemovedOldParser = Finder; //follow RemovedOld queue + RemovedOldParser->Next = nullptr; + } + Finder = FinderPrev->Next; + } + } + } +} + +void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From) +{ + HYAMNMAIL Temp; + while (From != nullptr) { + Temp = From; + From = From->Next; + DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Temp); + } +} + +void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0) +{ + uint32_t Number = Which->Number; + HYAMNMAIL Parser; + + if (*From == Which) { + Parser = Which->Next; + *From = Parser; + } + else { + for (Parser = *From; Which != Parser->Next; Parser = Parser->Next) + if (mode && (Parser->Number > Number)) Parser->Number--; + if (mode && (Parser->Number > Number)) Parser->Number--; + Parser->Next = Parser->Next->Next; + Parser = Which->Next; + } + if (mode) + for (; Parser != nullptr; Parser = Parser->Next) + if (Parser->Number > Number) Parser->Number--; +} + +void DeleteMessagesFromQueue(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0) +{ + HYAMNMAIL Parser; + + for (Parser = Which; Parser != nullptr; Parser = Parser->Next) + DeleteMessageFromQueueFcn(From, Parser, mode); +} + +HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID) +{ + HYAMNMAIL Browser; + + for (Browser = From; Browser != nullptr; Browser = Browser->Next) + if (0 == mir_strcmp(Browser->ID, ID)) + break; + return Browser; +} + +void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head) +{ + try { + char *finder = stream; + char *prev1, *prev2, *prev3; + struct CMimeItem *Item = nullptr; + + while (finder <= (stream + len)) { + while (ENDLINEWS(finder)) finder++; + + //at the start of line + if (DOTLINE(finder + 1)) //at the end of stream + break; + + prev1 = finder; + + while (*finder != ':' && !EOS(finder)) finder++; + if (!EOS(finder)) + prev2 = finder++; + else + break; + + while (WS(finder) && !EOS(finder)) finder++; + if (!EOS(finder)) + prev3 = finder; + else + break; + + do { + if (ENDLINEWS(finder)) finder += 2; //after endline information continues + while (!ENDLINE(finder) && !EOS(finder)) finder++; + } while (ENDLINEWS(finder)); + + if (Item != nullptr) { + if (nullptr == (Item->Next = new struct CMimeItem)) + break; + Item = Item->Next; + } + else { + Item = new CMimeItem; + *head = Item; + } + + Item->Next = nullptr; + Item->name = new char[prev2 - prev1 + 1]; + mir_strncpy(Item->name, prev1, prev2 - prev1 + 1); + Item->value = new char[finder - prev3 + 1]; + mir_strncpy(Item->value, prev3, finder - prev3 + 1); + + if (EOS(finder)) + break; + finder++; + if (ENDLINE(finder)) { + finder++; + if (ENDLINE(finder)) { + // end of headers. message body begins + finder++; + if (ENDLINE(finder))finder++; + prev1 = finder; + while (!DOTLINE(finder + 1))finder++; + if (ENDLINE(finder))finder--; + prev2 = finder; + if (prev2 > prev1) { // yes, we have body + if (nullptr == (Item->Next = new struct CMimeItem)) break; // Cant create new item?! + Item = Item->Next; + Item->Next = nullptr;//just in case; + Item->name = new char[5]; strncpy(Item->name, "Body", 5); + Item->value = new char[prev2 - prev1]; + mir_strncpy(Item->value, prev1, prev2 - prev1 - 1); + } + break; // there is nothing else + } + } + } + } + catch (...) { + MessageBoxA(nullptr, "Translate header error", "", 0); + } +} + +HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From) +{ + HYAMNMAIL FirstMail, Browser = nullptr; + + for (FirstMail = nullptr; From != nullptr; From = From->Next) { + if ((From->Flags & (YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE)) && !(From->Flags & YAMN_MSG_DELETED)) { + if (FirstMail == nullptr) { + FirstMail = Browser = new YAMNMAIL; + if (FirstMail == nullptr) + break; + } + else { + Browser->Next = new YAMNMAIL; + Browser = Browser->Next; + } + Browser->ID = new char[mir_strlen(From->ID) + 1]; + mir_strcpy(Browser->ID, From->ID); + Browser->Number = From->Number; + Browser->Flags = From->Flags; + } + } + return FirstMail; +} + +void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode) +{ + HYAMNMAIL msgq; + + for (msgq = (HYAMNMAIL)From; msgq != nullptr; msgq = msgq->Next) { + if ((FlagsSet == (msgq->Flags & FlagsSet)) && (0 == (msgq->Flags & FlagsNotSet))) { + if (mode) + msgq->Flags = msgq->Flags | FlagsToSetRemove; + else + msgq->Flags = msgq->Flags & ~FlagsToSetRemove; + } + } +} diff --git a/protocols/YAMN/src/mails/mime.cpp b/protocols/YAMN/src/mails/mime.cpp index 69099af808..2a2e7b4665 100644 --- a/protocols/YAMN/src/mails/mime.cpp +++ b/protocols/YAMN/src/mails/mime.cpp @@ -1,695 +1,695 @@ -/* - * This code implements retrieving info from MIME header - * - * (c) majvan 2002-2004 - */ - -#include "../stdafx.h" - - //-------------------------------------------------------------------------------------------------- - - //Copies one string to another - // srcstart- source string - // srcend- address to the end of source string - // dest- pointer that stores new allocated string that contains copy of source string - // mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' characters (or '<' and '>') if they are at start and end of source string -void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode); - -//Extracts email address (finds nick name and mail and then stores them to strings) -// finder- source string -// storeto- pointer that receives address of mail string -// storetonick- pointer that receives address of nickname -void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick); - -//Extracts simple text from string -// finder- source string -// storeto- pointer that receives address of string -void ExtractStringFromLine(char *finder, char **storeto); - -//Extracts some item from content-type string -//Example: ContentType string: "TEXT/PLAIN; charset=US-ASCII", item:"charset=", returns: "US-ASCII" -// ContetType- content-type string -// value- string item -// returns extracted string (or NULL when not found) -char *ExtractFromContentType(char *ContentType, char *value); - -//Extracts info from header text into header members -//Note that this function as well as struct CShortHeadwer can be always changed, because there are many items to extract -//(e.g. the X-Priority and Importance and so on) -// items- translated header (see TranslateHeaderFcn) -// head- header to be filled with values extracted from items -void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head); - -//Extracts header to mail using ExtractShortHeader fcn. -// items- translated header (see TranslateHeaderFcn) -// CP- codepage used when no default found -// head- header to be filled with values extracted from items, in unicode (wide char) -void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head); - -//Deletes items in CShortHeader structure -// head- structure whose items are deleted -void DeleteShortHeaderContent(struct CShortHeader *head); - -//Deletes list of YAMN_MIMENAMES structures -// Names- pointer to first item of list -void DeleteNames(CMimeNames *Names); - -//Deletes list of YAMN_MIMESHORTNAMES structures -// Names- pointer to first item of list -void DeleteShortNames(CShortNames *Names); - -//Makes a string lowercase -// string- string to be lowercased -void inline ToLower(char *string); - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode) -{ - char *dst; - - if (dest == nullptr) - return; - if (srcstart >= srcend) - return; - - if ((mode == MIME_MAIL) && (((*srcstart == '"') && (*(srcend - 1) == '"')) || ((*srcstart == '<') && (*(srcend - 1) == '>')))) { - srcstart++; - srcend--; - } - - if (srcstart >= srcend) - return; - - if (nullptr != *dest) - delete[] * dest; - if (nullptr == (*dest = new char[srcend - srcstart + 1])) - return; - - dst = *dest; - - for (; srcstart < srcend; dst++, srcstart++) { - if (ENDLINE(srcstart)) { - while (ENDLINE(srcstart) || WS(srcstart)) srcstart++; - *dst = ' '; - srcstart--; //because at the end of "for loop" we increment srcstart - } - else - *dst = *srcstart; - } - *dst = 0; -} - -void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick) -{ - if (finder == nullptr) { - *storeto = *storetonick = nullptr; - return; - } - while (WS(finder)) finder++; - if ((*finder) != '<') { - char *finderend = finder + 1; - do { - if (ENDLINEWS(finderend)) //after endline information continues - finderend += 2; - while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string - } while (ENDLINEWS(finderend)); - finderend--; - while (WS(finderend) || ENDLINE(finderend)) finderend--; //find the end of text, no whitespace - if (*finderend != '>') //not '>' at the end of line - CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL); - else //at the end of line, there's '>' - { - char *finder2 = finderend; - while ((*finder2 != '<') && (finder2 > finder)) finder2--; //go to matching '<' or to the start - CopyToHeader(finder2, finderend + 1, storeto, MIME_MAIL); - if (*finder2 == '<') //if we found '<', the rest copy as from nick - { - finder2--; - while (WS(finder2) || ENDLINE(finder2)) finder2--; //parse whitespace - CopyToHeader(finder, finder2 + 1, storetonick, MIME_MAIL); //and store nickname - } - } - } - else { - char *finderend = finder + 1; - do { - if (ENDLINEWS(finderend)) //after endline information continues - finderend += 2; - while (!ENDLINE(finderend) && (*finderend != '>') && !EOS(finderend)) finderend++; //seek to the matching < or to the end of line or to the end of string - } while (ENDLINEWS(finderend)); - CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL); //go to first '>' or to the end and copy - finder = finderend + 1; - while (WS(finder)) finder++; //parse whitespace - if (!ENDLINE(finder) && !EOS(finder)) //if there are chars yet, it's nick - { - finderend = finder + 1; - while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string - finderend--; - while (WS(finderend)) finderend--; //find the end of line, no whitespace - CopyToHeader(finder, finderend + 1, storetonick, MIME_MAIL); - } - } -} - -void ExtractStringFromLine(char *finder, char **storeto) -{ - if (finder == nullptr) { - *storeto = nullptr; - return; - } - while (WS(finder)) finder++; - char *finderend = finder; - - do { - if (ENDLINEWS(finderend)) finderend++; //after endline information continues - while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; - } while (ENDLINEWS(finderend)); - finderend--; - while (WS(finderend)) finderend--; //find the end of line, no whitespace - CopyToHeader(finder, finderend + 1, storeto, MIME_PLAIN); -} - -char *ExtractFromContentType(char *ContentType, char *value) -{ - char *lowered = _strdup(ContentType); - ToLower(lowered); - char *finder = strstr(lowered, value); - if (finder == nullptr) { - free(lowered); - return nullptr; - } - finder = finder - lowered + ContentType; - free(lowered); - - char *temp, *copier; - char *CopiedString; - - temp = finder - 1; - while ((temp > ContentType) && WS(temp)) temp--; //now we have to find, if the word "Charset=" is located after ';' like "; Charset=" - if (*temp != ';' && !ENDLINE(temp) && temp != ContentType) - return nullptr; - finder = finder + mir_strlen(value); //jump over value string - - while (WS(finder)) finder++; //jump over whitespaces - temp = finder; - while (*temp != 0 && *temp != ';') temp++; //jump to the end of setting (to the next ;) - temp--; - while (WS(temp)) temp--; //remove whitespaces from the end - if (*finder == '\"') { //remove heading and tailing quotes - finder++; - if (*temp == '\"') temp--; - } - if (nullptr == (CopiedString = new char[++temp - finder + 1])) - return nullptr; - for (copier = CopiedString; finder != temp; *copier++ = *finder++); //copy string - *copier = 0; //and end it with zero character - - return CopiedString; -} - -void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head) -{ - for (; items != nullptr; items = items->Next) { - //at the start of line - //MessageBox(NULL,items->value,items->name,0); - if (0 == _strnicmp(items->name, "From", 4)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, ""); - #endif - ExtractAddressFromLine(items->value, &head->From, &head->FromNick); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Return-Path", 11)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, ""); - #endif - ExtractAddressFromLine(items->value, &head->ReturnPath, &head->ReturnPathNick); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Subject", 7)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, ""); - #endif - ExtractStringFromLine(items->value, &head->Subject); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Body", 4)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, ""); - #endif - ExtractStringFromLine(items->value, &head->Body); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Date", 4)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, ""); - #endif - ExtractStringFromLine(items->value, &head->Date); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Content-Type", 12)) { - if (items->value == nullptr) - continue; - - char *ContentType = nullptr, *CharSetStr; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, ""); - #endif - ExtractStringFromLine(items->value, &ContentType); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "\n"); - #endif - ToLower(ContentType); - if (nullptr != (CharSetStr = ExtractFromContentType(ContentType, "charset="))) { - head->CP = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr)); - delete[] CharSetStr; - } - delete[] ContentType; - } - else if (0 == _strnicmp(items->name, "Importance", 10)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, ""); - #endif - if (head->Priority != -1) { - if (0 == strncmp(items->value, "low", 3)) - head->Priority = 5; - else if (0 == strncmp(items->value, "normal", 6)) - head->Priority = 3; - else if (0 == strncmp(items->value, "high", 4)) - head->Priority = 1; - } - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "\n"); - #endif - } - else if (0 == _strnicmp(items->name, "X-Priority", 10)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, ""); - #endif - if ((*items->value >= '1') && (*items->value <= '5')) - head->Priority = *items->value - '0'; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "\n"); - #endif - } - - } -} - -void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head) -{ - struct CShortHeader ShortHeader; - - memset(&ShortHeader, 0, sizeof(struct CShortHeader)); - ShortHeader.Priority = ShortHeader.CP = -1; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "\n"); - #endif - ExtractShortHeader(items, &ShortHeader); - - head->Priority = ShortHeader.Priority == -1 ? 3 : ShortHeader.Priority; - CP = ShortHeader.CP == -1 ? CP : ShortHeader.CP; - #ifdef DEBUG_DECODE - if (NULL != ShortHeader.From) - DebugLog(DecodeFile, "%s%s%s%s%s%s\n"); - DebugLog(DecodeFile, "\n"); - #endif - - ConvertCodedStringToUnicode(ShortHeader.From, &head->From, CP, MIME_PLAIN); - - #ifdef DEBUG_DECODE - if (NULL != head->From) - DebugLogW(DecodeFile, L"%s\n", head->From); - #endif - ConvertCodedStringToUnicode(ShortHeader.FromNick, &head->FromNick, CP, MIME_MAIL); - #ifdef DEBUG_DECODE - if (NULL != head->FromNick) - DebugLogW(DecodeFile, L"%s\n", head->FromNick); - #endif - ConvertCodedStringToUnicode(ShortHeader.ReturnPath, &head->ReturnPath, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->ReturnPath) - DebugLogW(DecodeFile, L"%s\n", head->ReturnPath); - #endif - ConvertCodedStringToUnicode(ShortHeader.ReturnPathNick, &head->ReturnPathNick, CP, MIME_MAIL); - #ifdef DEBUG_DECODE - if (NULL != head->ReturnPathNick) - DebugLogW(DecodeFile, L"%s\n", head->ReturnPathNick); - #endif - ConvertCodedStringToUnicode(ShortHeader.Subject, &head->Subject, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->Subject) - DebugLogW(DecodeFile, L"%s\n", head->Subject); - #endif - ConvertCodedStringToUnicode(ShortHeader.Date, &head->Date, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->Date) - DebugLogW(DecodeFile, L"%s\n", head->Date); - #endif - - ConvertCodedStringToUnicode(ShortHeader.Body, &head->Body, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->Body) - DebugLogW(DecodeFile, L"%s\n", head->Body); - #endif - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "\n"); - #endif - - DeleteShortHeaderContent(&ShortHeader); - - // head->From=L"Frommmm"; - // head->Subject=L"Subject"; - return; -} - -void DeleteShortHeaderContent(struct CShortHeader *head) -{ - if (head->From != nullptr) delete[] head->From; - if (head->FromNick != nullptr) delete[] head->FromNick; - if (head->ReturnPath != nullptr) delete[] head->ReturnPath; - if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick; - if (head->Subject != nullptr) delete[] head->Subject; - if (head->Date != nullptr) delete[] head->Date; - if (head->To != nullptr) DeleteShortNames(head->To); - if (head->Cc != nullptr) DeleteShortNames(head->Cc); - if (head->Bcc != nullptr) DeleteShortNames(head->Bcc); - if (head->Body != nullptr) delete[] head->Body; -} - -void DeleteHeaderContent(struct CHeader *head) -{ - if (head->From != nullptr) delete[] head->From; - if (head->FromNick != nullptr) delete[] head->FromNick; - if (head->ReturnPath != nullptr) delete[] head->ReturnPath; - if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick; - if (head->Subject != nullptr) delete[] head->Subject; - if (head->Date != nullptr) delete[] head->Date; - if (head->Body != nullptr) delete[] head->Body; - if (head->To != nullptr) DeleteNames(head->To); - if (head->Cc != nullptr) DeleteNames(head->Cc); - if (head->Bcc != nullptr) DeleteNames(head->Bcc); -} - -void DeleteNames(CMimeNames *Names) -{ - CMimeNames *Parser = Names; - for (; Parser != nullptr; Parser = Parser->Next) { - if (Parser->Value != nullptr) - delete[] Parser->Value; - if (Parser->ValueNick != nullptr) - delete[] Parser->ValueNick; - - CMimeNames *Old = Parser; - Parser = Parser->Next; - delete Old; - } -} - -void DeleteShortNames(CShortNames *Names) -{ - CShortNames *Parser = Names; - for (; Parser != nullptr; Parser = Parser->Next) { - if (Parser->Value != nullptr) - delete[] Parser->Value; - if (Parser->ValueNick != nullptr) - delete[] Parser->ValueNick; - - CShortNames *Old = Parser; - Parser = Parser->Next; - delete Old; - } -} - - -void inline ToLower(char *string) -{ - for (; *string != 0; string++) - if (*string >= 'A' && *string <= 'Z') *string = *string - 'A' + 'a'; -} - -#define TE_UNKNOWN -#define TE_QUOTEDPRINTABLE 1 -#define TE_BASE64 2 -struct APartDataType -{ - char *Src;//Input - char *ContType; - int CodePage; - char *TransEnc; - uint8_t TransEncType; //TE_something - char *body; - int bodyLen; - wchar_t *wBody; -}; - - -void ParseAPart(APartDataType *data) -{ - size_t len = mir_strlen(data->Src); - try { - char *finder = data->Src; - char *prev1, *prev2, *prev3; - - while (finder <= (data->Src + len)) { - while (ENDLINEWS(finder)) finder++; - - //at the start of line - if (finder > data->Src) { - if (*(finder - 2) == '\r' || *(finder - 2) == '\n') - *(finder - 2) = 0; - if (*(finder - 1) == '\r' || *(finder - 1) == '\n') - *(finder - 1) = 0; - } - prev1 = finder; - - while (*finder != ':' && !EOS(finder) && !ENDLINE(finder)) finder++; - if (ENDLINE(finder) || EOS(finder)) { - // no ":" in the line? here the body begins; - data->body = prev1; - break; - } - prev2 = finder++; - - while (WS(finder) && !EOS(finder)) finder++; - if (!EOS(finder)) - prev3 = finder; - else - break; - - do { - if (ENDLINEWS(finder)) finder += 2; //after endline information continues - while (!ENDLINE(finder) && !EOS(finder)) finder++; - } while (ENDLINEWS(finder)); - - if (!_strnicmp(prev1, "Content-type", prev2 - prev1)) { - data->ContType = prev3; - } - else if (!_strnicmp(prev1, "Content-Transfer-Encoding", prev2 - prev1)) { - data->TransEnc = prev3; - } - - if (EOS(finder)) - break; - finder++; - if (ENDLINE(finder)) { - finder++; - if (ENDLINE(finder)) { - // end of headers. message body begins - if (finder > data->Src) { - if (*(finder - 2) == '\r' || *(finder - 2) == '\n') - *(finder - 2) = 0; - if (*(finder - 1) == '\r' || *(finder - 1) == '\n') - *(finder - 1) = 0; - } - finder++; - if (ENDLINE(finder))finder++; - prev1 = finder; - while (!EOS(finder + 1))finder++; - if (ENDLINE(finder))finder--; - prev2 = finder; - if (prev2 > prev1) { // yes, we have body - data->body = prev1; - } - break; // there is nothing else - } - } - } - } - catch (...) { - MessageBox(nullptr, TranslateT("Translate header error"), L"", 0); - } - if (data->body) data->bodyLen = (int)mir_strlen(data->body); -} - -//from decode.cpp -int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ); -int DecodeBase64(char *Src, char *Dst, int DstLen); -int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out); - -wchar_t *ParseMultipartBody(char *src, char *bond) -{ - char *srcback = _strdup(src); - size_t sizebond = mir_strlen(bond); - int numparts = 1; - int i; - char *courbond = srcback; - wchar_t *dest; - for (; (courbond = strstr(courbond, bond)); numparts++, courbond += sizebond); - APartDataType *partData = new APartDataType[numparts]; - memset(partData, 0, sizeof(APartDataType) * numparts); - partData[0].Src = courbond = srcback; - for (i = 1; (courbond = strstr(courbond, bond)); i++, courbond += sizebond) { - *(courbond - 2) = 0; - partData[i].Src = courbond + sizebond; - while (ENDLINE(partData[i].Src)) partData[i].Src++; - } - size_t resultSize = 0; - for (i = 0; i < numparts; i++) { - ParseAPart(&partData[i]); - if (partData[i].body) { - if (partData[i].TransEnc) { - if (!_stricmp(partData[i].TransEnc, "base64")) partData[i].TransEncType = TE_BASE64; - else if (!_stricmp(partData[i].TransEnc, "quoted-printable"))partData[i].TransEncType = TE_QUOTEDPRINTABLE; - } - if (partData[i].ContType) { - char *CharSetStr; - if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) { - partData[i].CodePage = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr)); - delete[] CharSetStr; - } - } - if (partData[i].ContType && !_strnicmp(partData[i].ContType, "text", 4)) { - char *localBody = nullptr; - switch (partData[i].TransEncType) { - case TE_BASE64: - { - int size = partData[i].bodyLen * 3 / 4 + 5; - localBody = new char[size + 1]; - DecodeBase64(partData[i].body, localBody, size); - }break; - case TE_QUOTEDPRINTABLE: - { - int size = partData[i].bodyLen + 2; - localBody = new char[size + 1]; - DecodeQuotedPrintable(partData[i].body, localBody, size, FALSE); - }break; - } - ConvertStringToUnicode(localBody ? localBody : partData[i].body, partData[i].CodePage, &partData[i].wBody); - if (localBody) delete[] localBody; - } - else if (partData[i].ContType && !_strnicmp(partData[i].ContType, "multipart/", 10)) { - //Multipart in mulitipart recursive? should be SPAM. Ah well - char *bondary = nullptr; - if (nullptr != (bondary = ExtractFromContentType(partData[i].ContType, "boundary="))) { - partData[i].wBody = ParseMultipartBody(partData[i].body, bondary); - delete[] bondary; - } - else goto FailBackRaw; //multipart with no boundary? badly formatted messages. - } - else { -FailBackRaw: - ConvertStringToUnicode(partData[i].body, partData[i].CodePage, &partData[i].wBody); - } - resultSize += mir_wstrlen(partData[i].wBody); - }// if (partData[i].body) - resultSize += 100 + 4 + 3; //cr+nl+100+ 3*bullet - } - dest = new wchar_t[resultSize + 1]; - size_t destpos = 0; - for (i = 0; i < numparts; i++) { - if (i) { // part before first boudary should not have headers - char infoline[1024]; size_t linesize = 0; - mir_snprintf(infoline, "%s %d", Translate("Part"), i); - linesize = mir_strlen(infoline); - if (partData[i].TransEnc) { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].TransEnc); - linesize = mir_strlen(infoline); - } - if (partData[i].ContType) { - char *CharSetStr = strchr(partData[i].ContType, ';'); - if (CharSetStr) { - CharSetStr[0] = 0; - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType); - linesize = mir_strlen(infoline); - partData[i].ContType = CharSetStr + 1; - if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", CharSetStr); - linesize = mir_strlen(infoline); - delete[] CharSetStr; - } - if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "name="))) { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; \"%s\"", CharSetStr); - linesize = mir_strlen(infoline); - delete[] CharSetStr; - } - } - else { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType); - linesize = mir_strlen(infoline); - } - } - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, ".\r\n"); - { - wchar_t *temp = nullptr; - dest[destpos] = dest[destpos + 1] = dest[destpos + 2] = 0x2022; // bullet; - destpos += 3; - ConvertStringToUnicode(infoline, CP_ACP, &temp); - size_t wsize = mir_wstrlen(temp); - mir_wstrcpy(&dest[destpos], temp); - destpos += wsize; - delete[] temp; - } - } // if (i) - - if (partData[i].wBody) { - size_t wsize = mir_wstrlen(partData[i].wBody); - mir_wstrcpy(&dest[destpos], partData[i].wBody); - destpos += wsize; - delete[] partData[i].wBody; - } - } - - free(srcback); - delete[] partData; - dest[resultSize] = 0;//just in case - return dest; -} +/* + * This code implements retrieving info from MIME header + * + * (c) majvan 2002-2004 + */ + +#include "../stdafx.h" + + //-------------------------------------------------------------------------------------------------- + + //Copies one string to another + // srcstart- source string + // srcend- address to the end of source string + // dest- pointer that stores new allocated string that contains copy of source string + // mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' characters (or '<' and '>') if they are at start and end of source string +void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode); + +//Extracts email address (finds nick name and mail and then stores them to strings) +// finder- source string +// storeto- pointer that receives address of mail string +// storetonick- pointer that receives address of nickname +void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick); + +//Extracts simple text from string +// finder- source string +// storeto- pointer that receives address of string +void ExtractStringFromLine(char *finder, char **storeto); + +//Extracts some item from content-type string +//Example: ContentType string: "TEXT/PLAIN; charset=US-ASCII", item:"charset=", returns: "US-ASCII" +// ContetType- content-type string +// value- string item +// returns extracted string (or NULL when not found) +char *ExtractFromContentType(char *ContentType, char *value); + +//Extracts info from header text into header members +//Note that this function as well as struct CShortHeadwer can be always changed, because there are many items to extract +//(e.g. the X-Priority and Importance and so on) +// items- translated header (see TranslateHeaderFcn) +// head- header to be filled with values extracted from items +void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head); + +//Extracts header to mail using ExtractShortHeader fcn. +// items- translated header (see TranslateHeaderFcn) +// CP- codepage used when no default found +// head- header to be filled with values extracted from items, in unicode (wide char) +void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head); + +//Deletes items in CShortHeader structure +// head- structure whose items are deleted +void DeleteShortHeaderContent(struct CShortHeader *head); + +//Deletes list of YAMN_MIMENAMES structures +// Names- pointer to first item of list +void DeleteNames(CMimeNames *Names); + +//Deletes list of YAMN_MIMESHORTNAMES structures +// Names- pointer to first item of list +void DeleteShortNames(CShortNames *Names); + +//Makes a string lowercase +// string- string to be lowercased +void inline ToLower(char *string); + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode) +{ + char *dst; + + if (dest == nullptr) + return; + if (srcstart >= srcend) + return; + + if ((mode == MIME_MAIL) && (((*srcstart == '"') && (*(srcend - 1) == '"')) || ((*srcstart == '<') && (*(srcend - 1) == '>')))) { + srcstart++; + srcend--; + } + + if (srcstart >= srcend) + return; + + if (nullptr != *dest) + delete[] * dest; + if (nullptr == (*dest = new char[srcend - srcstart + 1])) + return; + + dst = *dest; + + for (; srcstart < srcend; dst++, srcstart++) { + if (ENDLINE(srcstart)) { + while (ENDLINE(srcstart) || WS(srcstart)) srcstart++; + *dst = ' '; + srcstart--; //because at the end of "for loop" we increment srcstart + } + else + *dst = *srcstart; + } + *dst = 0; +} + +void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick) +{ + if (finder == nullptr) { + *storeto = *storetonick = nullptr; + return; + } + while (WS(finder)) finder++; + if ((*finder) != '<') { + char *finderend = finder + 1; + do { + if (ENDLINEWS(finderend)) //after endline information continues + finderend += 2; + while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string + } while (ENDLINEWS(finderend)); + finderend--; + while (WS(finderend) || ENDLINE(finderend)) finderend--; //find the end of text, no whitespace + if (*finderend != '>') //not '>' at the end of line + CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL); + else //at the end of line, there's '>' + { + char *finder2 = finderend; + while ((*finder2 != '<') && (finder2 > finder)) finder2--; //go to matching '<' or to the start + CopyToHeader(finder2, finderend + 1, storeto, MIME_MAIL); + if (*finder2 == '<') //if we found '<', the rest copy as from nick + { + finder2--; + while (WS(finder2) || ENDLINE(finder2)) finder2--; //parse whitespace + CopyToHeader(finder, finder2 + 1, storetonick, MIME_MAIL); //and store nickname + } + } + } + else { + char *finderend = finder + 1; + do { + if (ENDLINEWS(finderend)) //after endline information continues + finderend += 2; + while (!ENDLINE(finderend) && (*finderend != '>') && !EOS(finderend)) finderend++; //seek to the matching < or to the end of line or to the end of string + } while (ENDLINEWS(finderend)); + CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL); //go to first '>' or to the end and copy + finder = finderend + 1; + while (WS(finder)) finder++; //parse whitespace + if (!ENDLINE(finder) && !EOS(finder)) //if there are chars yet, it's nick + { + finderend = finder + 1; + while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string + finderend--; + while (WS(finderend)) finderend--; //find the end of line, no whitespace + CopyToHeader(finder, finderend + 1, storetonick, MIME_MAIL); + } + } +} + +void ExtractStringFromLine(char *finder, char **storeto) +{ + if (finder == nullptr) { + *storeto = nullptr; + return; + } + while (WS(finder)) finder++; + char *finderend = finder; + + do { + if (ENDLINEWS(finderend)) finderend++; //after endline information continues + while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; + } while (ENDLINEWS(finderend)); + finderend--; + while (WS(finderend)) finderend--; //find the end of line, no whitespace + CopyToHeader(finder, finderend + 1, storeto, MIME_PLAIN); +} + +char *ExtractFromContentType(char *ContentType, char *value) +{ + char *lowered = _strdup(ContentType); + ToLower(lowered); + char *finder = strstr(lowered, value); + if (finder == nullptr) { + free(lowered); + return nullptr; + } + finder = finder - lowered + ContentType; + free(lowered); + + char *temp, *copier; + char *CopiedString; + + temp = finder - 1; + while ((temp > ContentType) && WS(temp)) temp--; //now we have to find, if the word "Charset=" is located after ';' like "; Charset=" + if (*temp != ';' && !ENDLINE(temp) && temp != ContentType) + return nullptr; + finder = finder + mir_strlen(value); //jump over value string + + while (WS(finder)) finder++; //jump over whitespaces + temp = finder; + while (*temp != 0 && *temp != ';') temp++; //jump to the end of setting (to the next ;) + temp--; + while (WS(temp)) temp--; //remove whitespaces from the end + if (*finder == '\"') { //remove heading and tailing quotes + finder++; + if (*temp == '\"') temp--; + } + if (nullptr == (CopiedString = new char[++temp - finder + 1])) + return nullptr; + for (copier = CopiedString; finder != temp; *copier++ = *finder++); //copy string + *copier = 0; //and end it with zero character + + return CopiedString; +} + +void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head) +{ + for (; items != nullptr; items = items->Next) { + //at the start of line + //MessageBox(NULL,items->value,items->name,0); + if (0 == _strnicmp(items->name, "From", 4)) { + if (items->value == nullptr) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, ""); + #endif + ExtractAddressFromLine(items->value, &head->From, &head->FromNick); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, "\n"); + #endif + } + else if (0 == _strnicmp(items->name, "Return-Path", 11)) { + if (items->value == nullptr) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, ""); + #endif + ExtractAddressFromLine(items->value, &head->ReturnPath, &head->ReturnPathNick); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, "\n"); + #endif + } + else if (0 == _strnicmp(items->name, "Subject", 7)) { + if (items->value == nullptr) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, ""); + #endif + ExtractStringFromLine(items->value, &head->Subject); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, "\n"); + #endif + } + else if (0 == _strnicmp(items->name, "Body", 4)) { + if (items->value == nullptr) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, ""); + #endif + ExtractStringFromLine(items->value, &head->Body); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, "\n"); + #endif + } + else if (0 == _strnicmp(items->name, "Date", 4)) { + if (items->value == nullptr) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, ""); + #endif + ExtractStringFromLine(items->value, &head->Date); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, "\n"); + #endif + } + else if (0 == _strnicmp(items->name, "Content-Type", 12)) { + if (items->value == nullptr) + continue; + + char *ContentType = nullptr, *CharSetStr; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, ""); + #endif + ExtractStringFromLine(items->value, &ContentType); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, "\n"); + #endif + ToLower(ContentType); + if (nullptr != (CharSetStr = ExtractFromContentType(ContentType, "charset="))) { + head->CP = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr)); + delete[] CharSetStr; + } + delete[] ContentType; + } + else if (0 == _strnicmp(items->name, "Importance", 10)) { + if (items->value == nullptr) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, ""); + #endif + if (head->Priority != -1) { + if (0 == strncmp(items->value, "low", 3)) + head->Priority = 5; + else if (0 == strncmp(items->value, "normal", 6)) + head->Priority = 3; + else if (0 == strncmp(items->value, "high", 4)) + head->Priority = 1; + } + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, "\n"); + #endif + } + else if (0 == _strnicmp(items->name, "X-Priority", 10)) { + if (items->value == nullptr) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, ""); + #endif + if ((*items->value >= '1') && (*items->value <= '5')) + head->Priority = *items->value - '0'; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, "\n"); + #endif + } + + } +} + +void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head) +{ + struct CShortHeader ShortHeader; + + memset(&ShortHeader, 0, sizeof(struct CShortHeader)); + ShortHeader.Priority = ShortHeader.CP = -1; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, "\n"); + #endif + ExtractShortHeader(items, &ShortHeader); + + head->Priority = ShortHeader.Priority == -1 ? 3 : ShortHeader.Priority; + CP = ShortHeader.CP == -1 ? CP : ShortHeader.CP; + #ifdef DEBUG_DECODE + if (NULL != ShortHeader.From) + DebugLog(DecodeFile, "%s%s%s%s%s%s\n"); + DebugLog(DecodeFile, "\n"); + #endif + + ConvertCodedStringToUnicode(ShortHeader.From, &head->From, CP, MIME_PLAIN); + + #ifdef DEBUG_DECODE + if (NULL != head->From) + DebugLogW(DecodeFile, L"%s\n", head->From); + #endif + ConvertCodedStringToUnicode(ShortHeader.FromNick, &head->FromNick, CP, MIME_MAIL); + #ifdef DEBUG_DECODE + if (NULL != head->FromNick) + DebugLogW(DecodeFile, L"%s\n", head->FromNick); + #endif + ConvertCodedStringToUnicode(ShortHeader.ReturnPath, &head->ReturnPath, CP, MIME_PLAIN); + #ifdef DEBUG_DECODE + if (NULL != head->ReturnPath) + DebugLogW(DecodeFile, L"%s\n", head->ReturnPath); + #endif + ConvertCodedStringToUnicode(ShortHeader.ReturnPathNick, &head->ReturnPathNick, CP, MIME_MAIL); + #ifdef DEBUG_DECODE + if (NULL != head->ReturnPathNick) + DebugLogW(DecodeFile, L"%s\n", head->ReturnPathNick); + #endif + ConvertCodedStringToUnicode(ShortHeader.Subject, &head->Subject, CP, MIME_PLAIN); + #ifdef DEBUG_DECODE + if (NULL != head->Subject) + DebugLogW(DecodeFile, L"%s\n", head->Subject); + #endif + ConvertCodedStringToUnicode(ShortHeader.Date, &head->Date, CP, MIME_PLAIN); + #ifdef DEBUG_DECODE + if (NULL != head->Date) + DebugLogW(DecodeFile, L"%s\n", head->Date); + #endif + + ConvertCodedStringToUnicode(ShortHeader.Body, &head->Body, CP, MIME_PLAIN); + #ifdef DEBUG_DECODE + if (NULL != head->Body) + DebugLogW(DecodeFile, L"%s\n", head->Body); + #endif + + #ifdef DEBUG_DECODE + DebugLog(DecodeFile, "\n"); + #endif + + DeleteShortHeaderContent(&ShortHeader); + + // head->From=L"Frommmm"; + // head->Subject=L"Subject"; + return; +} + +void DeleteShortHeaderContent(struct CShortHeader *head) +{ + if (head->From != nullptr) delete[] head->From; + if (head->FromNick != nullptr) delete[] head->FromNick; + if (head->ReturnPath != nullptr) delete[] head->ReturnPath; + if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick; + if (head->Subject != nullptr) delete[] head->Subject; + if (head->Date != nullptr) delete[] head->Date; + if (head->To != nullptr) DeleteShortNames(head->To); + if (head->Cc != nullptr) DeleteShortNames(head->Cc); + if (head->Bcc != nullptr) DeleteShortNames(head->Bcc); + if (head->Body != nullptr) delete[] head->Body; +} + +void DeleteHeaderContent(struct CHeader *head) +{ + if (head->From != nullptr) delete[] head->From; + if (head->FromNick != nullptr) delete[] head->FromNick; + if (head->ReturnPath != nullptr) delete[] head->ReturnPath; + if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick; + if (head->Subject != nullptr) delete[] head->Subject; + if (head->Date != nullptr) delete[] head->Date; + if (head->Body != nullptr) delete[] head->Body; + if (head->To != nullptr) DeleteNames(head->To); + if (head->Cc != nullptr) DeleteNames(head->Cc); + if (head->Bcc != nullptr) DeleteNames(head->Bcc); +} + +void DeleteNames(CMimeNames *Names) +{ + CMimeNames *Parser = Names; + for (; Parser != nullptr; Parser = Parser->Next) { + if (Parser->Value != nullptr) + delete[] Parser->Value; + if (Parser->ValueNick != nullptr) + delete[] Parser->ValueNick; + + CMimeNames *Old = Parser; + Parser = Parser->Next; + delete Old; + } +} + +void DeleteShortNames(CShortNames *Names) +{ + CShortNames *Parser = Names; + for (; Parser != nullptr; Parser = Parser->Next) { + if (Parser->Value != nullptr) + delete[] Parser->Value; + if (Parser->ValueNick != nullptr) + delete[] Parser->ValueNick; + + CShortNames *Old = Parser; + Parser = Parser->Next; + delete Old; + } +} + + +void inline ToLower(char *string) +{ + for (; *string != 0; string++) + if (*string >= 'A' && *string <= 'Z') *string = *string - 'A' + 'a'; +} + +#define TE_UNKNOWN +#define TE_QUOTEDPRINTABLE 1 +#define TE_BASE64 2 +struct APartDataType +{ + char *Src;//Input + char *ContType; + int CodePage; + char *TransEnc; + uint8_t TransEncType; //TE_something + char *body; + int bodyLen; + wchar_t *wBody; +}; + + +void ParseAPart(APartDataType *data) +{ + size_t len = mir_strlen(data->Src); + try { + char *finder = data->Src; + char *prev1, *prev2, *prev3; + + while (finder <= (data->Src + len)) { + while (ENDLINEWS(finder)) finder++; + + //at the start of line + if (finder > data->Src) { + if (*(finder - 2) == '\r' || *(finder - 2) == '\n') + *(finder - 2) = 0; + if (*(finder - 1) == '\r' || *(finder - 1) == '\n') + *(finder - 1) = 0; + } + prev1 = finder; + + while (*finder != ':' && !EOS(finder) && !ENDLINE(finder)) finder++; + if (ENDLINE(finder) || EOS(finder)) { + // no ":" in the line? here the body begins; + data->body = prev1; + break; + } + prev2 = finder++; + + while (WS(finder) && !EOS(finder)) finder++; + if (!EOS(finder)) + prev3 = finder; + else + break; + + do { + if (ENDLINEWS(finder)) finder += 2; //after endline information continues + while (!ENDLINE(finder) && !EOS(finder)) finder++; + } while (ENDLINEWS(finder)); + + if (!_strnicmp(prev1, "Content-type", prev2 - prev1)) { + data->ContType = prev3; + } + else if (!_strnicmp(prev1, "Content-Transfer-Encoding", prev2 - prev1)) { + data->TransEnc = prev3; + } + + if (EOS(finder)) + break; + finder++; + if (ENDLINE(finder)) { + finder++; + if (ENDLINE(finder)) { + // end of headers. message body begins + if (finder > data->Src) { + if (*(finder - 2) == '\r' || *(finder - 2) == '\n') + *(finder - 2) = 0; + if (*(finder - 1) == '\r' || *(finder - 1) == '\n') + *(finder - 1) = 0; + } + finder++; + if (ENDLINE(finder))finder++; + prev1 = finder; + while (!EOS(finder + 1))finder++; + if (ENDLINE(finder))finder--; + prev2 = finder; + if (prev2 > prev1) { // yes, we have body + data->body = prev1; + } + break; // there is nothing else + } + } + } + } + catch (...) { + MessageBox(nullptr, TranslateT("Translate header error"), L"", 0); + } + if (data->body) data->bodyLen = (int)mir_strlen(data->body); +} + +//from decode.cpp +int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ); +int DecodeBase64(char *Src, char *Dst, int DstLen); +int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out); + +wchar_t *ParseMultipartBody(char *src, char *bond) +{ + char *srcback = _strdup(src); + size_t sizebond = mir_strlen(bond); + int numparts = 1; + int i; + char *courbond = srcback; + wchar_t *dest; + for (; (courbond = strstr(courbond, bond)); numparts++, courbond += sizebond); + APartDataType *partData = new APartDataType[numparts]; + memset(partData, 0, sizeof(APartDataType) * numparts); + partData[0].Src = courbond = srcback; + for (i = 1; (courbond = strstr(courbond, bond)); i++, courbond += sizebond) { + *(courbond - 2) = 0; + partData[i].Src = courbond + sizebond; + while (ENDLINE(partData[i].Src)) partData[i].Src++; + } + size_t resultSize = 0; + for (i = 0; i < numparts; i++) { + ParseAPart(&partData[i]); + if (partData[i].body) { + if (partData[i].TransEnc) { + if (!_stricmp(partData[i].TransEnc, "base64")) partData[i].TransEncType = TE_BASE64; + else if (!_stricmp(partData[i].TransEnc, "quoted-printable"))partData[i].TransEncType = TE_QUOTEDPRINTABLE; + } + if (partData[i].ContType) { + char *CharSetStr; + if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) { + partData[i].CodePage = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr)); + delete[] CharSetStr; + } + } + if (partData[i].ContType && !_strnicmp(partData[i].ContType, "text", 4)) { + char *localBody = nullptr; + switch (partData[i].TransEncType) { + case TE_BASE64: + { + int size = partData[i].bodyLen * 3 / 4 + 5; + localBody = new char[size + 1]; + DecodeBase64(partData[i].body, localBody, size); + }break; + case TE_QUOTEDPRINTABLE: + { + int size = partData[i].bodyLen + 2; + localBody = new char[size + 1]; + DecodeQuotedPrintable(partData[i].body, localBody, size, FALSE); + }break; + } + ConvertStringToUnicode(localBody ? localBody : partData[i].body, partData[i].CodePage, &partData[i].wBody); + if (localBody) delete[] localBody; + } + else if (partData[i].ContType && !_strnicmp(partData[i].ContType, "multipart/", 10)) { + //Multipart in mulitipart recursive? should be SPAM. Ah well + char *bondary = nullptr; + if (nullptr != (bondary = ExtractFromContentType(partData[i].ContType, "boundary="))) { + partData[i].wBody = ParseMultipartBody(partData[i].body, bondary); + delete[] bondary; + } + else goto FailBackRaw; //multipart with no boundary? badly formatted messages. + } + else { +FailBackRaw: + ConvertStringToUnicode(partData[i].body, partData[i].CodePage, &partData[i].wBody); + } + resultSize += mir_wstrlen(partData[i].wBody); + }// if (partData[i].body) + resultSize += 100 + 4 + 3; //cr+nl+100+ 3*bullet + } + dest = new wchar_t[resultSize + 1]; + size_t destpos = 0; + for (i = 0; i < numparts; i++) { + if (i) { // part before first boudary should not have headers + char infoline[1024]; size_t linesize = 0; + mir_snprintf(infoline, "%s %d", Translate("Part"), i); + linesize = mir_strlen(infoline); + if (partData[i].TransEnc) { + mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].TransEnc); + linesize = mir_strlen(infoline); + } + if (partData[i].ContType) { + char *CharSetStr = strchr(partData[i].ContType, ';'); + if (CharSetStr) { + CharSetStr[0] = 0; + mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType); + linesize = mir_strlen(infoline); + partData[i].ContType = CharSetStr + 1; + if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) { + mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", CharSetStr); + linesize = mir_strlen(infoline); + delete[] CharSetStr; + } + if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "name="))) { + mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; \"%s\"", CharSetStr); + linesize = mir_strlen(infoline); + delete[] CharSetStr; + } + } + else { + mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType); + linesize = mir_strlen(infoline); + } + } + mir_snprintf(infoline + linesize, _countof(infoline) - linesize, ".\r\n"); + { + wchar_t *temp = nullptr; + dest[destpos] = dest[destpos + 1] = dest[destpos + 2] = 0x2022; // bullet; + destpos += 3; + ConvertStringToUnicode(infoline, CP_ACP, &temp); + size_t wsize = mir_wstrlen(temp); + mir_wstrcpy(&dest[destpos], temp); + destpos += wsize; + delete[] temp; + } + } // if (i) + + if (partData[i].wBody) { + size_t wsize = mir_wstrlen(partData[i].wBody); + mir_wstrcpy(&dest[destpos], partData[i].wBody); + destpos += wsize; + delete[] partData[i].wBody; + } + } + + free(srcback); + delete[] partData; + dest[resultSize] = 0;//just in case + return dest; +} -- cgit v1.2.3