summaryrefslogtreecommitdiff
path: root/protocols/YAMN/src/mails
diff options
context:
space:
mode:
authorKirill Volinsky <mataes2007@gmail.com>2012-10-14 09:45:11 +0000
committerKirill Volinsky <mataes2007@gmail.com>2012-10-14 09:45:11 +0000
commit4b6899c098f97960bf58456313ac8d643336dcd0 (patch)
treee04b9a7e1ddcff868fe81c2a6db3716c49d11c2f /protocols/YAMN/src/mails
parente179ffc995c96568bfdce46ac73f58d569166f05 (diff)
YAMN: folders restructurization
git-svn-id: http://svn.miranda-ng.org/main/trunk@1919 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/YAMN/src/mails')
-rw-r--r--protocols/YAMN/src/mails/decode.cpp558
-rw-r--r--protocols/YAMN/src/mails/m_decode.h25
-rw-r--r--protocols/YAMN/src/mails/mails.cpp499
-rw-r--r--protocols/YAMN/src/mails/mime.cpp732
4 files changed, 1814 insertions, 0 deletions
diff --git a/protocols/YAMN/src/mails/decode.cpp b/protocols/YAMN/src/mails/decode.cpp
new file mode 100644
index 0000000000..867ed7ff25
--- /dev/null
+++ b/protocols/YAMN/src/mails/decode.cpp
@@ -0,0 +1,558 @@
+/*
+ * 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 "../yamn.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 = (sizeof(CodePageNamesAll)/sizeof(CodePageNamesAll[0]));
+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 **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 **storeto,DWORD 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])==NULL)
+ 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=(char)0;
+
+#ifdef DEBUG_DECODECODEPAGE
+ DebugLog(DecodeFile,"<CodePage>%s</CodePage>",pout);
+#endif
+ for (int i=0;i<CPLENALL;i++) {
+ size_t len = strlen(CodePageNamesAll[i].NameBase);
+ if (0==strncmp(pout,CodePageNamesAll[i].NameBase,len)) {
+ if (0==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,"<Decode Quoted><Input>%s</Input>",Src);
+#endif
+ for (int Counter=0;((char)*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=(char)0;
+#ifdef DEBUG_DECODEQUOTED
+ DebugLog(DecodeFile,"<Output>%s</Output></Decode Quoted>",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,"<Decode Base64><Input>\n%s\n</Input>\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,"<Output>\n%s\n</Output></Decode Base64>",DstTemp);
+#endif
+ return 1;
+}
+
+
+
+int ConvertStringToUnicode(char *stream,unsigned int cp,WCHAR **out)
+{
+ CPINFO CPInfo;
+ WCHAR *temp,*src=*out,*dest;
+ size_t outlen;
+ int streamlen,Index;
+
+ //codepages, which require to have set 0 in dwFlags parameter when calling MultiByteToWideChar
+ DWORD 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,"<CodePage #>%d</CodePage #>",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,NULL,0);
+ else
+ streamlen=MultiByteToWideChar(cp,MB_USEGLYPHCHARS,stream,-1,NULL,0);
+
+ if (*out!=NULL)
+ outlen=wcslen(*out);
+ else
+ outlen=0;
+ temp=new WCHAR[streamlen+outlen+1];
+
+ if (*out!=NULL)
+ {
+ for (dest=temp;*src!=(WCHAR)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 **storeto,DWORD cp,int mode)
+{
+ char *start=stream,*finder,*finderend;
+ char Encoding=0;
+ char *DecodedResult=NULL;
+
+ if (stream==NULL)
+ return;
+
+ while(WS(start)) start++;
+ WCHAR *tempstore=0;
+ if (!ConvertStringToUnicode(stream,cp,&tempstore))return;
+
+ size_t tempstoreLength = wcslen(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=(DWORD)GetCharsetFromString(finder,finderend-finder)))
+ cp=CP_ACP;
+ if (Encoding!=0)
+ {
+ int size,codeend;
+ char *pcodeend;
+
+ 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--;
+ }
+ //*finderend=(char)0;
+ 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;
+ }
+ if (DecodedResult!=NULL)
+ delete[] DecodedResult;
+ 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=strlen(DecodedResult);
+ DecodedResult[len]=' ';
+ DecodedResult[len+1]=0;
+ finderend++;
+ }
+ WCHAR *oneWord=0;
+ if (ConvertStringToUnicode(DecodedResult,cp,&oneWord)) {
+ size_t len = wcslen(oneWord);
+ memcpy(&tempstore[outind],oneWord,len*sizeof(WCHAR));
+ outind += len;
+ }
+ delete oneWord;
+ oneWord = 0;
+ delete[] DecodedResult; DecodedResult = 0;
+ 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/m_decode.h b/protocols/YAMN/src/mails/m_decode.h
new file mode 100644
index 0000000000..e6d2b52fae
--- /dev/null
+++ b/protocols/YAMN/src/mails/m_decode.h
@@ -0,0 +1,25 @@
+#ifndef __DECODE_H
+#define __DECODE_H
+
+#include "../debug.h"
+
+#define DOTLINE(s) ((((s)[-2]=='\r') || ((s)[-2]=='\n')) && ((s)[-1]=='.') && (((s)[0]=='\r') || ((s)[0]=='\n') || ((s)[0]=='\0'))) // be careful, it's different to ESR's pop3.c ;-)
+#define ENDLINE(s) (((s)[0]=='\r') || ((s)[0]=='\n')) //endline
+#define WS(s) (((s)[0]==' ') || ((s)[0]=='\t')) //whitespace
+#define ENDLINEWS(s) ((((s)[0]=='\r') || ((s)[0]=='\n')) && (((((s)[1]=='\r') || ((s)[1]=='\n')) && (((s)[2]==' ') || ((s)[2]=='\t'))) || (((s)[1]==' ') || ((s)[1]=='\t')))) //endline+whitespace: enters(CR or LF and their combinations) followed by space or tab
+#define EOS(s) ((s)[0]==0) //end of string (stream)
+
+#define CODES(s) ((s[0]=='=') && (s[1]=='?')) //start of coded string
+#define CODEE(s) ((s[0]=='?') && (s[1]=='=')) //end of coded string
+#define CODED(s) (s[0]=='?') //code delimiter
+
+#define MIME_PLAIN 1
+#define MIME_MAIL 2
+
+struct cptable
+{
+ char *name;
+ unsigned int ID;
+};
+
+#endif
diff --git a/protocols/YAMN/src/mails/mails.cpp b/protocols/YAMN/src/mails/mails.cpp
new file mode 100644
index 0000000000..af0f3d2329
--- /dev/null
+++ b/protocols/YAMN/src/mails/mails.cpp
@@ -0,0 +1,499 @@
+/*
+ * This code implements retrieving info from MIME header
+ *
+ * (c) majvan 2002-2004
+ */
+
+#pragma warning( disable : 4290 )
+#include "../yamn.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(HACCOUNT 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(HACCOUNT 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,DWORD FlagsSet,DWORD FlagsNotSet,DWORD 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)
+{
+ HACCOUNT Account=(HACCOUNT)wParam;
+ DWORD MailVersion=(DWORD)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!=NULL)
+ {
+ if (Account->Plugin->MailFcn->NewMailFcnPtr!=NULL)
+ {
+//Let plugin create its own structure, which can be derived from CAccount structure
+ if (NULL==(NewMail=Account->Plugin->MailFcn->NewMailFcnPtr(Account,YAMN_MAILVERSION)))
+ return NULL;
+ }
+ else
+ {
+//We suggest plugin uses standard CAccount structure, so we create it
+ if (NULL==(NewMail=new YAMNMAIL))
+//If not created successfully
+ return NULL;
+ NewMail->MailData=NULL;
+ }
+//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!=NULL){
+ if (Plugin->MailFcn->DeleteMailFcnPtr!=NULL) {
+ //Let plugin delete its own CMimeMsgQueue derived structure
+ Plugin->MailFcn->DeleteMailFcnPtr(OldMail);
+ return 1;
+ }
+ }
+ if (OldMail->MailData!=NULL) {
+ if (OldMail->MailData->Body!=NULL)
+ delete[] OldMail->MailData->Body;
+ if ((TH=OldMail->MailData->TranslatedHeader)!=NULL)
+ for (;OldMail->MailData->TranslatedHeader!=NULL;) {
+ TH=TH->Next;
+ if (OldMail->MailData->TranslatedHeader->name!=NULL)
+ delete[] OldMail->MailData->TranslatedHeader->name;
+ if (OldMail->MailData->TranslatedHeader->value!=NULL)
+ delete[] OldMail->MailData->TranslatedHeader->value;
+ delete OldMail->MailData->TranslatedHeader;
+ OldMail->MailData->TranslatedHeader=TH;
+ }
+ delete OldMail->MailData;
+ }
+ if (OldMail->ID!=NULL)
+ 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!=NULL) Finder=Finder->Next;
+ Finder->Next=second;
+}
+
+INT_PTR LoadMailDataSvc(WPARAM wParam,LPARAM lParam)
+{
+ HYAMNMAIL Mail=(HYAMNMAIL)wParam;
+ DWORD MailVersion=(DWORD)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 wParam,LPARAM)
+{
+ HYAMNMAIL Mail=(HYAMNMAIL)wParam;
+
+//now we should delete structure from memory, but it will be made in future YAMN version
+ return 1;
+}
+
+INT_PTR SaveMailDataSvc(WPARAM wParam,LPARAM lParam)
+{
+ HYAMNMAIL Mail=(HYAMNMAIL)wParam;
+ DWORD MailVersion=(DWORD)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(HACCOUNT 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 =NULL;
+ HYAMNMAIL RemovedNewParser =NULL;
+ if (RemovedOld!=NULL) *RemovedOld=NULL;
+ if (RemovedNew!=NULL) *RemovedNew=NULL;
+
+ for (FinderPrev=NULL,Finder=*OldQueue;Finder!=NULL;)
+ {
+ 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=NULL,Parser=*NewQueue;Parser!=NULL;ParserPrev=Parser,Parser=Parser->Next)
+ {
+ if (Parser->Flags & YAMN_MSG_DELETED)
+ continue;
+
+ if (Parser->ID==NULL) //simply ignore the message, that has not filled its ID
+ continue;
+
+ if (0==strcmp(Parser->ID,Finder->ID)) //search for equal message in new queue
+ break;
+ }
+ if (Parser!=NULL) //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==NULL) //delete from new queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Parser);
+ else //or move to RemovedNew
+ {
+ if (RemovedNewParser==NULL) //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=NULL;
+ }
+ 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==NULL) //delete from old queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Finder);
+ else //or move to RemovedOld
+ {
+ if (RemovedOldParser==NULL) //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=NULL;
+ }
+ Finder=*OldQueue;
+ }
+ else
+ {
+ FinderPrev->Next=Finder->Next;
+ if (RemovedOld==NULL) //delete from old queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Finder);
+ else //or move to RemovedOld
+ {
+ if (RemovedOldParser==NULL) //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=NULL;
+ }
+ Finder=FinderPrev->Next;
+ }
+ }
+ }
+}
+
+void WINAPI DeleteMessagesToEndFcn(HACCOUNT Account,HYAMNMAIL From)
+{
+ HYAMNMAIL Temp;
+ while(From!=NULL)
+ {
+ Temp=From;
+ From=From->Next;
+ DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Temp);
+ }
+}
+
+void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From,HYAMNMAIL Which,int mode=0)
+{
+ DWORD 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!=NULL;Parser=Parser->Next)
+ if (Parser->Number>Number) Parser->Number--;
+}
+
+void DeleteMessagesFromQueue(HYAMNMAIL *From,HYAMNMAIL Which,int mode=0)
+{
+ HYAMNMAIL Parser;
+
+ for (Parser=Which;Parser!=NULL;Parser=Parser->Next)
+ DeleteMessageFromQueueFcn(From,Parser,mode);
+}
+
+HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From,char *ID)
+{
+ HYAMNMAIL Browser;
+
+ for (Browser=From;Browser!=NULL;Browser=Browser->Next)
+ if (0==lstrcmpA(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=NULL;
+
+ 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!=NULL)
+ {
+ if (NULL==(Item->Next=new struct CMimeItem))
+ break;
+ Item=Item->Next;
+ }
+ else
+ {
+ Item = new CMimeItem;
+ *head = Item;
+ }
+
+ Item->Next=NULL;
+ Item->name=new char [prev2-prev1+1];
+ lstrcpynA(Item->name,prev1,prev2-prev1+1);
+ Item->value=new char [finder-prev3+1];
+ lstrcpynA(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 (NULL==(Item->Next=new struct CMimeItem)) break; // Cant create new item?!
+ Item=Item->Next;
+ Item->Next=NULL;//just in case;
+ Item->name=new char[5]; strncpy(Item->name,"Body",5);
+ Item->value=new char [prev2-prev1];
+ lstrcpynA(Item->value,prev1,prev2-prev1-1);
+ }
+ break; // there is nothing else
+ }
+ }
+ }
+ }
+ catch(...)
+ {
+ MessageBoxA(NULL,"Translate header error","",0);
+ }
+}
+
+HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From)
+{
+ HYAMNMAIL FirstMail,Browser;
+
+ for (FirstMail=NULL;From!=NULL;From=From->Next)
+ {
+ if ((From->Flags & (YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE)) && !(From->Flags & YAMN_MSG_DELETED))
+ {
+ if (FirstMail==NULL)
+ {
+ FirstMail=Browser=new YAMNMAIL;
+ if (FirstMail==NULL)
+ break;
+ }
+ else
+ {
+ Browser->Next=new YAMNMAIL;
+ Browser=Browser->Next;
+ }
+ Browser->ID=new char[strlen(From->ID)+1];
+ strcpy(Browser->ID,From->ID);
+ Browser->Number=From->Number;
+ Browser->Flags=From->Flags;
+ }
+ }
+ return FirstMail;
+}
+
+void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From,DWORD FlagsSet,DWORD FlagsNotSet,DWORD FlagsToSetRemove,int mode)
+{
+ HYAMNMAIL msgq;
+
+ for (msgq=(HYAMNMAIL)From;msgq!=NULL;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
new file mode 100644
index 0000000000..2a66b80e2b
--- /dev/null
+++ b/protocols/YAMN/src/mails/mime.cpp
@@ -0,0 +1,732 @@
+/*
+ * This code implements retrieving info from MIME header
+ *
+ * (c) majvan 2002-2004
+ */
+
+#pragma warning( disable : 4290 )
+#include "../yamn.h"
+
+//- imported ---------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+extern SWMRG *AccountBrowserSO;
+extern struct WndHandles *MessageWnd;
+
+extern int GetCharsetFromString(char *input,size_t size);
+extern void SendMsgToRecepients(struct WndHandles *FirstWin,UINT msg,WPARAM wParam,LPARAM lParam);
+extern void ConvertCodedStringToUnicode(char *stream,WCHAR **storeto,DWORD cp,int mode);
+extern DWORD WINAPI MailBrowser(LPVOID Param);
+extern DWORD WINAPI NoNewMailProc(LPVOID Param);
+extern DWORD WINAPI BadConnection(LPVOID Param);
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+//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(PYAMN_MIMENAMES Names);
+
+//Deletes list of YAMN_MIMESHORTNAMES structures
+// Names- pointer to first item of list
+void DeleteShortNames(PYAMN_MIMESHORTNAMES 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==NULL)
+ return;
+ if (srcstart>=srcend)
+ return;
+
+ if ((mode==MIME_MAIL) && (((*srcstart=='"') && (*(srcend-1)=='"')) || ((*srcstart=='<') && (*(srcend-1)=='>'))))
+ {
+ srcstart++;
+ srcend--;
+ }
+
+ if (srcstart>=srcend)
+ return;
+
+ if (NULL!=*dest)
+ delete[] *dest;
+ if (NULL==(*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==NULL)
+ {
+ *storeto=*storetonick=NULL;
+ 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==NULL)
+ {
+ *storeto=NULL;
+ 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==NULL){
+ free (lowered);
+ return NULL;
+ }
+ 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 NULL;
+ finder=finder+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 (NULL==(CopiedString=new char[++temp-finder+1]))
+ return NULL;
+ 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!=NULL;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==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting from>");
+ #endif
+ ExtractAddressFromLine(items->value,&head->From,&head->FromNick);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\n");
+ #endif
+ }
+ else if (0==_strnicmp(items->name,"Return-Path",11))
+ {
+ if (items->value==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting return-path>");
+ #endif
+ ExtractAddressFromLine(items->value,&head->ReturnPath,&head->ReturnPathNick);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\n");
+ #endif
+ }
+ else if (0==_strnicmp(items->name,"Subject",7))
+ {
+ if (items->value==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting subject>");
+ #endif
+ ExtractStringFromLine(items->value,&head->Subject);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\n");
+ #endif
+ }
+ else if (0==_strnicmp(items->name,"Body",4))
+ {
+ if (items->value==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting body>");
+ #endif
+ ExtractStringFromLine(items->value,&head->Body);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\n");
+ #endif
+ }
+ else if (0==_strnicmp(items->name,"Date",4))
+ {
+ if (items->value==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting date>");
+ #endif
+ ExtractStringFromLine(items->value,&head->Date);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\n");
+ #endif
+ }
+ else if (0==_strnicmp(items->name,"Content-Type",12))
+ {
+ if (items->value==NULL)
+ continue;
+
+ char *ContentType=NULL,*CharSetStr;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting Content-Type>");
+ #endif
+ ExtractStringFromLine(items->value,&ContentType);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\n");
+ #endif
+ ToLower(ContentType);
+ if (NULL!=(CharSetStr=ExtractFromContentType(ContentType,"charset=")))
+ {
+ head->CP=GetCharsetFromString(CharSetStr,strlen(CharSetStr));
+ delete[] CharSetStr;
+ }
+ delete[] ContentType;
+ }
+ else if (0==_strnicmp(items->name,"Importance",10))
+ {
+ if (items->value==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting importance>");
+ #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,"</Extracting>\n");
+ #endif
+ }
+ else if (0==_strnicmp(items->name,"X-Priority",10))
+ {
+ if (items->value==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<X-Priority>");
+ #endif
+ if ((*items->value>='1') && (*items->value<='5'))
+ head->Priority=*items->value-'0';
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\n");
+ #endif
+ }
+
+ }
+}
+
+void ExtractHeader(struct CMimeItem *items,int &CP,struct CHeader *head)
+{
+ struct CShortHeader ShortHeader;
+
+ ZeroMemory(&ShortHeader,sizeof(struct CShortHeader));
+ ShortHeader.Priority=ShortHeader.CP=-1;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting header>\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,"<Decoded from>%s</Decoded)\n",ShortHeader.From);
+ if (NULL!=ShortHeader.FromNick)
+ DebugLog(DecodeFile,"<Decoded from-nick>%s</Decoded)\n",ShortHeader.FromNick);
+ if (NULL!=ShortHeader.ReturnPath)
+ DebugLog(DecodeFile,"<Decoded return-path>%s</Decoded)\n",ShortHeader.ReturnPath);
+ if (NULL!=ShortHeader.ReturnPathNick)
+ DebugLog(DecodeFile,"<Decoded return-path nick>%s</Decoded)\n",ShortHeader.ReturnPathNick);
+ if (NULL!=ShortHeader.Subject)
+ DebugLog(DecodeFile,"<Decoded subject>%s</Decoded)\n",ShortHeader.Subject);
+ if (NULL!=ShortHeader.Date)
+ DebugLog(DecodeFile,"<Decoded date>%s</Decoded)\n",ShortHeader.Date);
+ DebugLog(DecodeFile,"</Extracting header>\n");
+ DebugLog(DecodeFile,"<Convert>\n");
+ #endif
+
+ ConvertCodedStringToUnicode(ShortHeader.From,&head->From,CP,MIME_PLAIN);
+
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->From)
+ DebugLogW(DecodeFile,L"<Converted from>%s</Converted>\n",head->From);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.FromNick,&head->FromNick,CP,MIME_MAIL);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->FromNick)
+ DebugLogW(DecodeFile,L"<Converted from-nick>%s</Converted>\n",head->FromNick);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.ReturnPath,&head->ReturnPath,CP,MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->ReturnPath)
+ DebugLogW(DecodeFile,L"<Converted return-path>%s</Converted>\n",head->ReturnPath);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.ReturnPathNick,&head->ReturnPathNick,CP,MIME_MAIL);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->ReturnPathNick)
+ DebugLogW(DecodeFile,L"<Converted return-path nick>%s</Converted>\n",head->ReturnPathNick);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.Subject,&head->Subject,CP,MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->Subject)
+ DebugLogW(DecodeFile,L"<Converted subject>%s</Converted>\n",head->Subject);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.Date,&head->Date,CP,MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->Date)
+ DebugLogW(DecodeFile,L"<Converted date>%s</Converted>\n",head->Date);
+ #endif
+
+ ConvertCodedStringToUnicode(ShortHeader.Body,&head->Body,CP,MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->Body)
+ DebugLogW(DecodeFile,L"<Converted Body>%s</Converted>\n",head->Body);
+ #endif
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Convert>\n");
+ #endif
+
+ DeleteShortHeaderContent(&ShortHeader);
+
+// head->From=L"Frommmm";
+// head->Subject=L"Subject";
+ return;
+}
+
+void DeleteShortHeaderContent(struct CShortHeader *head)
+{
+ if (head->From!=NULL) delete[] head->From;
+ if (head->FromNick!=NULL) delete[] head->FromNick;
+ if (head->ReturnPath!=NULL) delete[] head->ReturnPath;
+ if (head->ReturnPathNick!=NULL) delete[] head->ReturnPathNick;
+ if (head->Subject!=NULL) delete[] head->Subject;
+ if (head->Date!=NULL) delete[] head->Date;
+ if (head->To!=NULL) DeleteShortNames(head->To);
+ if (head->Cc!=NULL) DeleteShortNames(head->Cc);
+ if (head->Bcc!=NULL) DeleteShortNames(head->Bcc);
+ if (head->Body!=NULL) delete[] head->Body;
+}
+
+void DeleteHeaderContent(struct CHeader *head)
+{
+ if (head->From!=NULL) delete[] head->From;
+ if (head->FromNick!=NULL) delete[] head->FromNick;
+ if (head->ReturnPath!=NULL) delete[] head->ReturnPath;
+ if (head->ReturnPathNick!=NULL) delete[] head->ReturnPathNick;
+ if (head->Subject!=NULL) delete[] head->Subject;
+ if (head->Date!=NULL) delete[] head->Date;
+ if (head->Body!=NULL) delete[] head->Body;
+ if (head->To!=NULL) DeleteNames(head->To);
+ if (head->Cc!=NULL) DeleteNames(head->Cc);
+ if (head->Bcc!=NULL) DeleteNames(head->Bcc);
+}
+
+void DeleteNames(PYAMN_MIMENAMES Names)
+{
+ PYAMN_MIMENAMES Parser=Names,Old;
+ for (;Parser!=NULL;Parser=Parser->Next)
+ {
+ if (Parser->Value!=NULL)
+ delete[] Parser->Value;
+ if (Parser->ValueNick!=NULL)
+ delete[] Parser->ValueNick;
+ Old=Parser;
+ Parser=Parser->Next;
+ delete Old;
+ }
+}
+
+void DeleteShortNames(PYAMN_MIMESHORTNAMES Names)
+{
+ PYAMN_MIMESHORTNAMES Parser=Names,Old;
+ for (;Parser!=NULL;Parser=Parser->Next)
+ {
+ if (Parser->Value!=NULL)
+ delete[] Parser->Value;
+ if (Parser->ValueNick!=NULL)
+ delete[] Parser->ValueNick;
+ 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;
+ BYTE TransEncType; //TE_something
+ char *body;
+ int bodyLen;
+ WCHAR *wBody;
+};
+
+
+void ParseAPart(APartDataType *data)
+{
+ size_t len = 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(NULL,_T("Translate header error"),_T(""),0);
+ }
+ if (data->body) data->bodyLen = (int)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 **out);
+
+WCHAR *ParseMultipartBody(char *src, char *bond)
+{
+ char *srcback = _strdup(src);
+ size_t sizebond = strlen(bond);
+ int numparts = 1;
+ int i;
+ char *courbond = srcback;
+ WCHAR *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 (NULL!=(CharSetStr=ExtractFromContentType(partData[i].ContType,"charset=")))
+ {
+ partData[i].CodePage=GetCharsetFromString(CharSetStr,strlen(CharSetStr));
+ delete[] CharSetStr;
+ }
+ }
+ if (partData[i].ContType && !_strnicmp(partData[i].ContType,"text",4)) {
+ char *localBody=0;
+ 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=NULL;
+ if (NULL!=(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 += wcslen(partData[i].wBody);
+ }// if (partData[i].body)
+ resultSize += 100+4+3; //cr+nl+100+ 3*bullet
+ }
+ dest = new WCHAR[resultSize+1];
+ size_t destpos = 0;
+ for (i=0;i<numparts;i++) {
+ if (i){ // part before first boudary should not have headers
+ char infoline[104]; size_t linesize = 0;
+ _snprintf(infoline,100,"%s %d",Translate("Part"),i);
+ linesize = strlen(infoline);
+ if (partData[i].TransEnc){
+ _snprintf(infoline+linesize,100-linesize,"; %s",partData[i].TransEnc);
+ linesize = strlen(infoline);
+ }
+ if (partData[i].ContType){
+ char *CharSetStr=strchr(partData[i].ContType,';');
+ if (CharSetStr){
+ CharSetStr[0]=0;
+ _snprintf(infoline+linesize,100-linesize,"; %s",partData[i].ContType);
+ linesize = strlen(infoline);
+ partData[i].ContType=CharSetStr+1;
+ if (NULL!=(CharSetStr=ExtractFromContentType(partData[i].ContType,"charset=")))
+ {
+ _snprintf(infoline+linesize,100-linesize,"; %s",CharSetStr);
+ linesize = strlen(infoline);
+ delete[] CharSetStr;
+ }
+ if (NULL!=(CharSetStr=ExtractFromContentType(partData[i].ContType,"name=")))
+ {
+ _snprintf(infoline+linesize,100-linesize,"; \"%s\"",CharSetStr);
+ linesize = strlen(infoline);
+ delete[] CharSetStr;
+ }
+ } else {
+ _snprintf(infoline+linesize,100-linesize,"; %s",partData[i].ContType);
+ linesize = strlen(infoline);
+ }
+ }
+ sprintf(infoline+linesize,".\r\n");
+ {WCHAR *temp=0;
+ dest[destpos] = dest[destpos+1] = dest[destpos+2] = 0x2022; // bullet;
+ destpos+=3;
+ ConvertStringToUnicode(infoline,CP_ACP,&temp);
+ size_t wsize = wcslen(temp);
+ wcscpy(&dest[destpos],temp);
+ destpos += wsize;
+ delete[] temp;
+ }
+ } // if (i)
+ if (partData[i].wBody){
+ size_t wsize = wcslen(partData[i].wBody);
+ wcscpy(&dest[destpos],partData[i].wBody);
+ destpos += wsize;
+ delete[] partData[i].wBody;
+ }
+ }
+
+ free (srcback);
+ delete[] partData;
+ dest[resultSize] = 0;//just in case
+ return dest;
+}