From f04d64869f3b1de54fb343f28f955584780001b8 Mon Sep 17 00:00:00 2001 From: mataes2007 Date: Sat, 26 Nov 2011 15:41:10 +0000 Subject: Project folders rename part 3 git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@215 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- YAMN/mails/decode.cpp | 558 +++++++++++++++++++++++++++++++++ YAMN/mails/m_decode.h | 25 ++ YAMN/mails/m_mails.h | 285 +++++++++++++++++ YAMN/mails/mails.cpp | 499 ++++++++++++++++++++++++++++++ YAMN/mails/mime.cpp | 732 ++++++++++++++++++++++++++++++++++++++++++++ YAMN/mails/test/header.txt | 28 ++ YAMN/mails/test/header2.txt | 97 ++++++ YAMN/mails/test/readme.txt | 4 + YAMN/mails/test/test.cpp | 42 +++ YAMN/mails/test/test.dsp | 112 +++++++ YAMN/mails/test/test.dsw | 29 ++ 11 files changed, 2411 insertions(+) create mode 100644 YAMN/mails/decode.cpp create mode 100644 YAMN/mails/m_decode.h create mode 100644 YAMN/mails/m_mails.h create mode 100644 YAMN/mails/mails.cpp create mode 100644 YAMN/mails/mime.cpp create mode 100644 YAMN/mails/test/header.txt create mode 100644 YAMN/mails/test/header2.txt create mode 100644 YAMN/mails/test/readme.txt create mode 100644 YAMN/mails/test/test.cpp create mode 100644 YAMN/mails/test/test.dsp create mode 100644 YAMN/mails/test/test.dsw (limited to 'YAMN/mails') diff --git a/YAMN/mails/decode.cpp b/YAMN/mails/decode.cpp new file mode 100644 index 0000000..15c23e9 --- /dev/null +++ b/YAMN/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[]= +{ + {_T("ANSI"),_T(""),TRUE,CP_ACP}, + {_T("WINDOWS-1"),_T("250"),0,1250}, + {_T("WINDOWS-1"),_T("251"),0,1251}, + {_T("WINDOWS-1"),_T("252"),0,1252}, + {_T("WINDOWS-1"),_T("253"),0,1253}, + {_T("WINDOWS-1"),_T("254"),0,1254}, + {_T("WINDOWS-1"),_T("255"),0,1255}, + {_T("WINDOWS-1"),_T("256"),0,1256}, + {_T("WINDOWS-1"),_T("257"),0,1257}, + {_T("WINDOWS-1"),_T("258"),0,1258}, + {_T("CP1"),_T("250"),0,1250}, + {_T("CP1"),_T("251"),0,1251}, + {_T("CP1"),_T("252"),0,1252}, + {_T("CP1"),_T("253"),0,1253}, + {_T("CP1"),_T("254"),0,1254}, + {_T("CP1"),_T("255"),0,1255}, + {_T("CP1"),_T("256"),0,1256}, + {_T("CP1"),_T("257"),0,1257}, + {_T("CP1"),_T("258"),0,1258}, + {_T("ANSI-1"),_T("250"),0,1250}, + {_T("ANSI-1"),_T("251"),0,1251}, + {_T("ANSI-1"),_T("252"),0,1252}, + {_T("ANSI-1"),_T("253"),0,1253}, + {_T("ANSI-1"),_T("254"),0,1254}, + {_T("ANSI-1"),_T("255"),0,1255}, + {_T("ANSI-1"),_T("256"),0,1256}, + {_T("ANSI-1"),_T("257"),0,1257}, + {_T("ANSI-1"),_T("258"),0,1258}, + {_T("KOI8"),_T("-R"),0,20866}, + {_T("KOI8"),_T(""),0,20866}, + {_T("KOI8"),_T("-U"),0,21866}, + {_T("KOI8"),_T("-RU"),0,21866}, + {_T("US-"),_T("ASCII"),0,20127}, + {_T("CP"),_T("367"),0,20127}, + {_T("ASCII"),_T(""),0,20127}, + {_T("ASCII"),_T("7"),0,20127}, + {_T("ISO-8859"),_T("-1"),0,28591}, + {_T("ISO-8859"),_T("-2"),0,28592}, + {_T("ISO-8859"),_T("-3"),0,28593}, + {_T("ISO-8859"),_T("-4"),0,28594}, + {_T("ISO-8859"),_T("-5"),0,28595}, + {_T("ISO-8859"),_T("-6"),0,28596}, + {_T("ISO-8859"),_T("-7"),0,28597}, + {_T("ISO-8859"),_T("-8"),0,28598}, + {_T("ISO-8859"),_T("-9"),0,28599}, + {_T("ISO-8859"),_T("-15"),0,28605}, + {_T("ISO_8859"),_T("-1"),0,28591}, + {_T("ISO_8859"),_T("-2"),0,28592}, + {_T("ISO_8859"),_T("-3"),0,28593}, + {_T("ISO_8859"),_T("-4"),0,28594}, + {_T("ISO_8859"),_T("-5"),0,28595}, + {_T("ISO_8859"),_T("-6"),0,28596}, + {_T("ISO_8859"),_T("-7"),0,28597}, + {_T("ISO_8859"),_T("-8"),0,28598}, + {_T("ISO_8859"),_T("-9"),0,28599}, + {_T("ISO_8859"),_T("-15"),0,28605}, + {_T("ISO-"),_T("10646-USC2"),0,1200}, + {_T("ISO-2022"),_T("/2-JP"),0,50220}, + {_T("ISO-2022"),_T("-JP"),0,50221}, + {_T("ISO-2022"),_T("/JIS-JP"),0,50222}, + {_T("ISO-2022"),_T("-KR"),0,50225}, + {_T("ISO-2022"),_T("-CH(SP)"),0,50227}, + {_T("ISO-2022"),_T("-CH(TR)"),0,50229}, + {_T("UTF-"),_T("7"),0,65000}, + {_T("UTF-"),_T("8"),0,65001}, + {_T("ARAB-"),_T("TRANSPARENT"),0,710}, + {_T("ASMO-"),_T("TRANSPARENT"),0,720}, + {_T("ASMO-"),_T("449"),0,709}, + {_T("ASMO-"),_T("708"),0,708}, + {_T("BIG5"),_T(""),0,950}, + {_T("EUC-"),_T("CH(SP)"),0,51936}, + {_T("EUC-"),_T("CH(TR)"),0,51950}, + {_T("EUC-"),_T("JP"),0,51932}, + {_T("EUC-"),_T("KR"),0,51949}, + {_T("GB-"),_T("2312"),0,20936}, + {_T("GB"),_T("2312"),0,20936}, + {_T("HZGB-"),_T("2312"),0,52936}, + {_T("IBM-"),_T("037"),0,37}, + {_T("IBM-"),_T("290"),0,290}, + {_T("IBM-"),_T("437"),0,437}, + {_T("IBM-"),_T("500"),0,500}, + {_T("IBM-"),_T("775"),0,775}, + {_T("IBM-"),_T("850"),0,850}, + {_T("IBM-"),_T("852"),0,852}, + {_T("IBM-"),_T("855"),0,855}, + {_T("IBM-"),_T("857"),0,857}, + {_T("IBM-"),_T("860"),0,860}, + {_T("IBM-"),_T("861"),0,861}, + {_T("IBM-"),_T("862"),0,862}, + {_T("IBM-"),_T("863"),0,863}, + {_T("IBM-"),_T("864"),0,864}, + {_T("IBM-"),_T("865"),0,865}, + {_T("IBM-"),_T("866"),0,866}, + {_T("IBM-"),_T("869"),0,869}, + {_T("IBM-"),_T("870"),0,870}, + {_T("IBM-"),_T("875"),0,875}, + {_T("IBM-"),_T("1026"),0,1026}, + {_T("IBM-"),_T("273"),0,20273}, + {_T("IBM-"),_T("277"),0,20277}, + {_T("IBM-"),_T("278"),0,20278}, + {_T("IBM-"),_T("280"),0,20280}, + {_T("IBM-"),_T("284"),0,20284}, + {_T("IBM-"),_T("285"),0,20285}, + {_T("IBM-"),_T("290"),0,20290}, + {_T("IBM-"),_T("297"),0,20297}, + {_T("IBM-"),_T("420"),0,20420}, + {_T("IBM-"),_T("423"),0,20423}, + {_T("IBM-"),_T("871"),0,20871}, + {_T("IBM-"),_T("880"),0,20880}, + {_T("IBM-"),_T("905"),0,20905}, + {_T("IBM-"),_T("THAI"),0,20838}, + {_T("ISCII-"),_T("DEVANAGARI"),0,57002}, + {_T("ISCII-"),_T("BENGALI"),0,57003}, + {_T("ISCII-"),_T("TAMIL"),0,57004}, + {_T("ISCII-"),_T("TELUGU"),0,57005}, + {_T("ISCII-"),_T("ASSAMESE"),0,57006}, + {_T("ISCII-"),_T("ORIYA"),0,57007}, + {_T("ISCII-"),_T("KANNADA"),0,57008}, + {_T("ISCII-"),_T("MALAYALAM"),0,57009}, + {_T("ISCII-"),_T("GUJARATI"),0,57010}, + {_T("ISCII-"),_T("PUNJABI"),0,57011}, + {_T("KOR-"),_T("JOHAB"),0,1361}, + {_T("KSC-"),_T("5601"),0,1361}, + {_T("MAC-"),_T("ROMAN"),0,10000}, + {_T("MAC-"),_T("JP"),0,10001}, + {_T("MAC-"),_T("CH(SP)(BIG5)"),0,10002}, + {_T("MAC-"),_T("KR"),0,10003}, + {_T("MAC-"),_T("AR"),0,10004}, + {_T("MAC-"),_T("HW"),0,10005}, + {_T("MAC-"),_T("GR"),0,10006}, + {_T("MAC-"),_T("CY"),0,10007}, + {_T("MAC-"),_T("CH(SP)(GB2312)"),0,10008}, + {_T("MAC-"),_T("ROMANIA"),0,10010}, + {_T("MAC-"),_T("UA"),0,10017}, + {_T("MAC-"),_T("TH"),0,10021}, + {_T("MAC-"),_T("LAT2"),0,10029}, + {_T("MAC-"),_T("ICE"),0,10079}, + {_T("MAC-"),_T("TR"),0,10081}, + {_T("MAC-"),_T("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,"%s",pout); +#endif + for(int i=0;i='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;((char)*Src!=0) && DstLen && (Counter++%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 **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,"%d",cp); +#endif + + for(Index=0;Index tempstoreLength) break; + start++; + } + } + tempstore[outind] = 0; + *storeto = tempstore; +} diff --git a/YAMN/mails/m_decode.h b/YAMN/mails/m_decode.h new file mode 100644 index 0000000..e6d2b52 --- /dev/null +++ b/YAMN/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/YAMN/mails/m_mails.h b/YAMN/mails/m_mails.h new file mode 100644 index 0000000..e1826a1 --- /dev/null +++ b/YAMN/mails/m_mails.h @@ -0,0 +1,285 @@ +#ifndef __MAILS_H +#define __MAILS_H + +#include +#include +#include "../m_account.h" + +// +//================================== OTHER DEFINITIONS ======================================== +// + +typedef struct CShortNames +{ + char *Value; + char *ValueNick; + struct CShortNames *Next; +} YAMN_MIMESHORTNAMES,*PYAMN_MIMESHORTNAMES; + +typedef struct CNames +{ + WCHAR *Value; + WCHAR *ValueNick; + struct CNames *Next; +} YAMN_MIMENAMES,*PYAMN_MIMENAMES; + +struct CShortHeader +//this header is used in to get non-unicode data from mime header +{ + char *From; + char *FromNick; + char *ReturnPath; + char *ReturnPathNick; + char *Subject; + PYAMN_MIMESHORTNAMES To; + PYAMN_MIMESHORTNAMES Cc; + PYAMN_MIMESHORTNAMES Bcc; + char *Date; + char Priority; + char *Body; + + int CP; + + CShortHeader() {} + ~CShortHeader() {} +}; + +struct CHeader +//this header is used in miranda to store final results of mime reading in Unicode +{ + WCHAR *From; + WCHAR *FromNick; + WCHAR *ReturnPath; + WCHAR *ReturnPathNick; + WCHAR *Subject; + PYAMN_MIMENAMES To; + PYAMN_MIMENAMES Cc; + PYAMN_MIMENAMES Bcc; + WCHAR *Date; + TCHAR Priority; + WCHAR *Body; + + CHeader() {} + ~CHeader() {} +}; + +struct CMimeItem +{ + char *name; + char *value; + struct CMimeItem *Next; + CMimeItem(): name(NULL), value(NULL), Next(NULL){} +}; + +typedef struct CMailData //this is plugin-independent +{ +#define YAMN_MAILDATAVERSION 3 + + DWORD Size; + int CP; + + struct CMimeItem *TranslatedHeader; //MIME items + struct CMimeItem *Additional; //MIME items not read from server (custom, for filter plugins etc.) + char *Body; //Message body + + CMailData(): CP(-1), Size(0), TranslatedHeader(NULL), Body(NULL){} +} MAILDATA,*PMAILDATA; + +typedef struct CMimeMsgQueue +{ +#define YAMN_MAILVERSION 3 + char *ID; //The ID of mail. This ID identifies every mail in the account, so plugin should set it + + DWORD Number; + +#define YAMN_MSG_ANY 0xffffffff //any mail + +//The difference between new and unseen: when new mail is found in account, it becomes unseen and new. But in the next check, if the same mail is found, it is not new. +//However, when user was not near computer, he does not know about this mail- it is unseen. After user accepts, that he saw new mails, it becomes seen. +#define YAMN_MSG_NEW 0x80000000 //this mail is new +#define YAMN_MSG_UNSEEN 0x40000000 //this mail is mailbrowser unseen +#define YAMN_MSG_DISPLAY 0x20000000 //this mail can be displayed in mailbrowser +#define YAMN_MSG_POPUP 0x10000000 //this mail can be displayed in popup and can invoke a popup +#define YAMN_MSG_SYSTRAY 0x08000000 //this mail can invoke systray icon +#define YAMN_MSG_BROWSER 0x04000000 //this mail can run mailbrowser +#define YAMN_MSG_DISPLAYC 0x02000000 //this mail is inserted to browser mail counter system (the "Account - xx new mails, yy total" phrase) +#define YAMN_MSG_POPUPC 0x01000000 //this mail is inserted to popup counter system (the "Account - xx new mails, yy total" phrase) + +#define YAMN_MSG_SOUND 0x00800000 //this mail can "play sound" +#define YAMN_MSG_APP 0x00400000 //this mail can "launch application" +#define YAMN_MSG_NEVENT 0x00100000 //this mail can launch Miranda "new mail" event + +#define YAMN_MSG_VIRTUAL 0x00080000 //this mail is not real- does not exists + +#define YAMN_MSG_FILTERED 0x00040000 //this mail has been filtered + +#define YAMN_MSG_DELETETRASH 0x00020000 //this mail should be moved to the trash bin rather than really deleting from mailbox (this is only switch doing nothing, perhaps usefull for filter plugins) +#define YAMN_MSG_DELETED 0x00010000 //this mail is already deleted from server (also must be set virtual flag) (when doing synchronizations between 2 queues, YAMN then does not touch this mail) +#define YAMN_MSG_MEMDELETE 0x00008000 //this mail will be deleted immidiatelly from memory (and disk) when deleted from server (some opposite of YAMN_MSG_DELETED) +#define YAMN_MSG_USERDELETE 0x00004000 //this mail is about to delete from server (user deletes manually) +#define YAMN_MSG_AUTODELETE 0x00002000 //this mail is about to delete from server (plugin marks it for deleting) +#define YAMN_MSG_DELETEOK 0x00001000 //this mail is confirmed to delete (this flag must be set to delete this mail) + +#define YAMN_MSG_BODYREQUESTED 0x00000800 //user requested (part of) the body. In POP3 it should be (TOP ) +#define YAMN_MSG_BODYRECEIVED 0x00000200 //(part of) the body.received; +#define YAMN_MSG_STAYUNSEEN 0x00000400 //this mail stays unseen while user does not really see it + +#define YAMN_MSG_DELETE (YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE) + +#define YAMN_MSG_NORMALNEW (YAMN_MSG_NEW | YAMN_MSG_UNSEEN | YAMN_MSG_BROWSER | YAMN_MSG_DISPLAY | YAMN_MSG_DISPLAYC | YAMN_MSG_POPUP | YAMN_MSG_POPUPC | YAMN_MSG_SYSTRAY | YAMN_MSG_SOUND | YAMN_MSG_APP | YAMN_MSG_NEVENT | YAMN_MSG_MEMDELETE | YAMN_MSG_STAYUNSEEN) + +#define YAMN_MSG_FLAGSSET(maildata,flag) ((maildata & flag)==flag) + +#define YAMN_MSG_SPAML1 1 //spam level 1: notify, show in another color in mail browser +#define YAMN_MSG_SPAML2 2 //spam level 2: do not notify, show in another color in mail browser +#define YAMN_MSG_SPAML3 3 //spam level 3: delete, show in another color in mail browser that it was deleted, you do not need to set YAMN_MSG_AUTODELETE +#define YAMN_MSG_SPAML4 4 //spam level 4: delete, do not show, you do not need to set YAMN_MSG_AUTODELETE +#define YAMN_MSG_SPAMMASK 0x0000000F + +#define YAMN_MSG_SPAML(maildata,level) ((maildata & YAMN_MSG_SPAMMASK)==level) + DWORD Flags; +//Plugins can read mail data, but it can be NULL!!! So plugin should use Load and Save services to load or save data and Unload to release data from memory + PMAILDATA MailData; +//Here YAMN stores its own informations about this mail. Not usefull for plugins... +// void *YAMNData; + HWND MsgWindow; +//plugins can store here its own data + void *PluginData; + + CMimeMsgQueue(): ID(NULL), Number(0), Flags(0), MailData(NULL), MsgWindow(NULL), PluginData(NULL), Next(NULL){} + ~CMimeMsgQueue(){} + + struct CMimeMsgQueue *Next; +} YAMNMAIL,*HYAMNMAIL; + +#define LoadedMailData(x) (x->MailData!=NULL) + +// +//================================== YAMN MAIL SERVICES ================================== +// + +//CreateAccountMail Service +//Your plugin should call this to create new mail for your plugin. +//WPARAM- (HACCOUNT) Account handle +//LPARAM- CMailData version (use YAMN_MAILVERSION definition) +//returns pointer to (HYAMNMAIL) or pointer to your structure returned from imported NewMailFcnPtr, if implemented +#define MS_YAMN_CREATEACCOUNTMAIL "YAMN/Service/CreateMail" +#define CreateAccountMail(x) (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL,(WPARAM)x,(LPARAM)YAMN_MAILVERSION) + +//DeleteAccountMail Service +//Deletes plugin's mail from memory. You probably won't use this service, because it deletes only account +//without any synchronization. Use MS_YAMN_DELETEACCOUNT instead. Note that deleting mail is something like "this mail is +//not more in the account". +//WPARAM- (HYAMNPROTOPLUGIN) handle of plugin, which is going to delete mail +//LPARAM- (HYAMNMAIL) mail going to delete +//returns zero if failed, otherwise returns nonzero +#define MS_YAMN_DELETEACCOUNTMAIL "YAMN/Service/DeletePluginMail" +#define DeleteAccountMail(x,y) CallService(MS_YAMN_DELETEACCOUNTMAIL,(WPARAM)x,(LPARAM)y) + +//LoadMailData Service +//This service loads mail from standard YAMN storage (now it is 1 file, from which mails are loaded once at startup, but +//in the future it can be Miranda profile file or separate file (1 file per 1 mail). It depends on YAMN implementation... +//Use this function if you want to read or write to MailData member of mail structure. Please use synchronization obejcts +//before calling this service (so you must have read or write access to mails) +//WPARAM- (HYAMNMAIL) mail where to load data +//LPARAM- (DWORD) version of MAILDATA structure (use YAMN_MAILDATAVERSION definition) +//returns pointer to new allocated MailData structure (the same value as MailData member) +#define MS_YAMN_LOADMAILDATA "YAMN/Service/LoadMailData" +#define LoadMailData(x) (PMAILDATA)CallService(MS_YAMN_LOADMAILDATA,(WPARAM)x,(LPARAM)YAMN_MAILDATAVERSION) + +//UnloadMailData Service +//This service frees mail data from memory. It does not care if data were saved or not. So you should save mail before you +//release data from memory. +//WPARAM- (HYAMNMAIL) mail whose data are about to free +//LPARAM- nothing yet +//returns nonzero if success +#define MS_YAMN_UNLOADMAILDATA "YAMN/Service/UnloadMailData" +#define UnloadMailData(x) CallService(MS_YAMN_UNLOADMAILDATA,(WPARAM)x,(LPARAM)0) + +//SaveMailData Service +//This service saves mail to standard YAMN storage (when using now 1 book file, it does nothing, because save is done when +//using MS_YAMN_WRITEACCOUNT service. In the future, mail can be saved to Miranda profile or to separate file...) +//WPARAM- (HYAMNMAIL) mail to save +//LPARAM- (DWORD) version of MAILDATA structure (use YAMN_MAILDATAVERSION definition) +//returns ZERO! if succes +#define MS_YAMN_SAVEMAILDATA "YAMN/Service/SaveMailData" +#define SaveMailData(x) CallService(MS_YAMN_SAVEMAILDATA,(WPARAM)x,(LPARAM)YAMN_MAILDATAVERSION) + +// +//================================== FUNCTIONS DEFINITIONS ======================================== +// + +//typedef void (WINAPI *YAMN_SENDMESSAGEFCN)(UINT,WPARAM,LPARAM); +typedef void (WINAPI *YAMN_SYNCHROMIMEMSGSFCN)(HACCOUNT,HYAMNMAIL *,HYAMNMAIL *,HYAMNMAIL *,HYAMNMAIL *); +typedef void (WINAPI *YAMN_TRANSLATEHEADERFCN)(char *,int,struct CMimeItem **); +typedef void (WINAPI *YAMN_APPENDQUEUEFCN)(HYAMNMAIL,HYAMNMAIL); +typedef void (WINAPI *YAMN_DELETEMIMEQUEUEFCN)(HACCOUNT,HYAMNMAIL); +typedef void (WINAPI *YAMN_DELETEMIMEMESSAGEFCN)(HYAMNMAIL *,HYAMNMAIL,int); +typedef HYAMNMAIL (WINAPI *YAMN_FINDMIMEMESSAGEFCN)(HYAMNMAIL,char *); +typedef HYAMNMAIL (WINAPI *YAMN_CREATENEWDELETEQUEUEFCN)(HYAMNMAIL); +typedef void (WINAPI *YAMN_SETREMOVEQUEUEFLAGSFCN)(HYAMNMAIL,DWORD,DWORD,DWORD,int); + +// +//================================== QUICK FUNCTION CALL DEFINITIONS ======================================== +// + +//These are defininitions for YAMN exported functions. Your plugin can use them. +//pYAMNFcn is global variable, it is pointer to your structure containing YAMN functions. +//It is something similar like pluginLink variable in Miranda plugin. If you use +//this name of variable, you have already defined these functions and you can use them. +//It's similar to Miranda's CreateService function. + +//How to use YAMN functions: +//Create a structure containing pointer to functions you want to use in your plugin +//This structure can look something like this: +// +// struct +// { +// YAMN_SYNCHROMIMEMSGSFCN SynchroMessagesFcn; +// YAMN_APPENDQUEUEFCN AppendQueueFcn; +// } *pYAMNMailFcn; +// +//then you have to fill this structure with pointers... +//you have to use YAMN service to get pointer, like this (I wrote here all functions you may need, +//you can copy to your sources only those you need): +// +// pYAMNMailFcn->SynchroMessagesFcn=(YAMN_SYNCHROMIMEMSGSFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_SYNCHROMIMEMSGSID,(LPARAM)0); +// pYAMNMailFcn->TranslateHeaderFcn=(YAMN_TRANSLATEHEADERFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_TRANSLATEHEADERID,(LPARAM)0); +// pYAMNMailFcn->AppendQueueFcn=(YAMN_APPENDQUEUEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_APPENDQUEUEID,(LPARAM)0); +// pYAMNMailFcn->DeleteMessagesToEndFcn=(YAMN_DELETEMIMEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_DELETEMIMEQUEUEID,(LPARAM)0); +// pYAMNMailFcn->DeleteMessageFromQueueFcn=(YAMN_DELETEMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_DELETEMIMEMESSAGEID,(LPARAM)0); +// pYAMNMailFcn->FindMessageByIDFcn=(YAMN_FINDMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_FINDMIMEMESSAGEID,(LPARAM)0); +// pYAMNMailFcn->CreateNewDeleteQueueFcn=(YAMN_CREATENEWDELETEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_CREATENEWDELETEQUEUEID,(LPARAM)0); +// pYAMNMailFcn->SetRemoveQueueFlagsFcn=(YAMN_SETREMOVEQUEUEFLAGSFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_SETREMOVEQUEUEFLAGSID,(LPARAM)0); +// +// +//and in your plugin just simply use e.g.: +// +// DeleteMIMEQueue(MyAccount,OldMessages); //this command deletes all messages in the mail queue OldMessages +// + +#define YAMN_SYNCHROMIMEMSGSID "YAMN/SynchroMessages" +#define YAMN_TRANSLATEHEADERID "YAMN/TranslateHeader" +#define YAMN_APPENDQUEUEID "YAMN/AppendQueue" +#define YAMN_DELETEMIMEQUEUEID "YAMN/DeleteMIMEQueue" +#define YAMN_DELETEMIMEMESSAGEID "YAMN/DeleteMIMEMessage" +#define YAMN_FINDMIMEMESSAGEID "YAMN/FindMIMEMessageByID" +#define YAMN_CREATENEWDELETEQUEUEID "YAMN/CreateNewDeleteQueue" +#define YAMN_SETREMOVEQUEUEFLAGSID "YAMN/SetRemoveQueueFlags" + +#define YAMN_FLAG_REMOVE 0 +#define YAMN_FLAG_SET 1 + + +#define SynchroMessages(a,b,c,d,e) pYAMNMailFcn->SynchroMessagesFcn(a,b,c,d,e) +#define TranslateHeader(a,b,c) pYAMNMailFcn->TranslateHeaderFcn(a,b,c) +#define AppendQueue(x,y) pYAMNMailFcn->AppendQueueFcn(x,y) +#define DeleteMIMEQueue(x,y) pYAMNMailFcn->DeleteMessagesToEndFcn(x,y) +#define DeleteMIMEMessage(x,y) pYAMNMailFcn->DeleteMessageFromQueueFcn(x,y,0) +#define DeleteMIMEMessageEx(x,y,z) pYAMNMailFcn->DeleteMessageFromQueueFcn(x,y,z) +#define FindMIMEMessageByID(x,y) pYAMNMailFcn->FindMessageByIDFcn(x,y) +#define CreateNewDeleteQueue(x) pYAMNMailFcn->CreateNewDeleteQueueFcn(x) +#define SetQueueFlags(a,b,c,d) pYAMNMailFcn->SetRemoveQueueFlagsFcn(a,b,c,d,1) +#define RemoveQueueFlags(a,b,c,d) pYAMNMailFcn->SetRemoveQueueFlagsFcn(a,b,c,d,0) + +#endif diff --git a/YAMN/mails/mails.cpp b/YAMN/mails/mails.cpp new file mode 100644 index 0000000..b99a9fd --- /dev/null +++ b/YAMN/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==lstrcmp(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]; + lstrcpyn(Item->name,prev1,prev2-prev1+1); + Item->value=new char [finder-prev3+1]; + lstrcpyn(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]; + lstrcpyn(Item->value,prev1,prev2-prev1-1); + } + break; // there is nothing else + } + } + } + } + catch(...) + { + MessageBox(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/YAMN/mails/mime.cpp b/YAMN/mails/mime.cpp new file mode 100644 index 0000000..f2364c9 --- /dev/null +++ b/YAMN/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' 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,""); + #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==NULL) + 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==NULL) + 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==NULL) + 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==NULL) + 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==NULL) + continue; + + char *ContentType=NULL,*CharSetStr; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,""); + #endif + ExtractStringFromLine(items->value,&ContentType); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\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,""); + #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==NULL) + 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; + + ZeroMemory(&ShortHeader,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!=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 +Delivered-To: pablo@decode.com.ar +Received: (qmail 5438 invoked by uid 618); 5 Sep 2003 19:49:16 -0000 +Mailing-List: contact foromundial-help@decode.com.ar; run by ezmlm +Precedence: bulk +X-No-Archive: yes +List-Post: +List-Help: +List-Unsubscribe: +List-Subscribe: +X-Seq: 1047 +Delivered-To: mailing list foromundial@decode.com.ar +Received: (qmail 5432 invoked by uid 618); 5 Sep 2003 19:49:15 -0000 +X-Spam-Status: No, hits=3.9 required=7.5 +Message-Id: <4.2.1.20030905163128.00a998a0@mail.labsem.cetuc.puc-rio.br> +X-Sender: sandra@mail.labsem.cetuc.puc-rio.br +X-Mailer: QUALCOMM Windows Eudora Pro Version 4.2.1 +Date: Fri, 05 Sep 2003 16:48:12 -0300 +To: foromundial@decode.com.ar +From: "Sandra M. Landi" +Mime-Version: 1.0 +Content-Type: multipart/alternative; + boundary="=====================_4293080==_.ALT" +X-Antirelay: Good relay from local net2 139.82.127.0/26 +Subject: [foromundial-1047] frases para un viernes + + +. diff --git a/YAMN/mails/test/header2.txt b/YAMN/mails/test/header2.txt new file mode 100644 index 0000000..3ba81a2 --- /dev/null +++ b/YAMN/mails/test/header2.txt @@ -0,0 +1,97 @@ +Return-Path: +Received: [from megami.sprintserve.net (megami.sprintserve.net [207.142.136.160]) + by mail2.ba.psg.sk with ESMTP id i4FHNUY6018585 + for ; Sat, 15 May 2004 19:23:31 +0200] +X-Envelope-To: +Received: from miranda by megami.sprintserve.net with local (Exim 4.34) + id 1BP2sS-0006W6-MS + for om3tn@psg.sk; Sat, 15 May 2004 13:23:12 -0400 +To: Undisclosed-recipients:; +Subject: UpozornØn¡ na odpovØÔ v t‚matu - YAMN problem +Reply-to: forum@miranda-im.org +From: forum@miranda-im.org: +Message-ID: +MIME-Version: 1.0 +Content-type: text/plain; charset=Windows-1250 +Content-transfer-encoding: 8bit +Date: Sat, 15 May 2004 13:23:12 -0400 +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: PHP +X-MimeOLE: Produced By phpBB2 +X-MailScanner-Information: Please contact the ISP for more information +X-MailScanner: Found to be clean +X-AntiAbuse: This header was added to track abuse, please include it with any abuse report +X-AntiAbuse: Primary Hostname - megami.sprintserve.net +X-AntiAbuse: Original Domain - psg.sk +X-AntiAbuse: Originator/Caller UID/GID - [32110 32110] / [47 12] +X-AntiAbuse: Sender Address Domain - megami.sprintserve.net +X-Source: +X-Source-Args: +X-Source-Dir: +. + +Subject: UpozornØn¡ na odpovØÔ v t‚matu - YAMN problem + +Return-Path: +Received: [from megami.sprintserve.net (megami.sprintserve.net [207.142.136.160]) + by mail2.ba.psg.sk with ESMTP id i4FHX2Y6020695 + for ; Sat, 15 May 2004 19:33:03 +0200] +X-Envelope-To: +Received: from miranda by megami.sprintserve.net with local (Exim 4.34) + id 1BP31h-0001cs-Ai + for om3tn@psg.sk; Sat, 15 May 2004 13:32:45 -0400 +To: Undisclosed-recipients:; +Subject: UpozornØn¡ na odpovØÔ v t‚matu - YAMN problem +Reply-to: forum@miranda-im.org +From: forum@miranda-im.org +Message-ID: <0873b36d0931479c4ebe23ba71ff4810@forums.miranda-im.org> +MIME-Version: 1.0 +Content-type: text/plain; charset=Windows-1250 +Content-transfer-encoding: 8bit +Date: Sat, 15 May 2004 13:32:45 -0400 +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: PHP +X-MimeOLE: Produced By phpBB2 +X-MailScanner-Information: Please contact the ISP for more information +X-MailScanner: Found to be clean +X-AntiAbuse: This header was added to track abuse, please include it with any abuse report +X-AntiAbuse: Primary Hostname - megami.sprintserve.net +X-AntiAbuse: Original Domain - psg.sk +X-AntiAbuse: Originator/Caller UID/GID - [32110 32110] / [47 12] +X-AntiAbuse: Sender Address Domain - megami.sprintserve.net +X-Source: +X-Source-Args: +X-Source-Dir: + +. + +Received: by hplm (mbox om3tn) + (with POP3 daemon cucipop (v1.31 1998/05/13) Tue May 27 18:42:20 2003) +X-From_: HMF@hotbox.ru Tue May 20 18:11:44 2003 +Return-Path: +Received: from ns1.slovanet.net (ns1.slovanet.net [195.28.64.119]) + by hplm.psg.sk (8.12.9/8.12.7) with SMTP id h4KGBfxJ003732 + for ; Tue, 20 May 2003 18:11:44 +0200 +X-Envelope-To: +Received: (qmail 6339 invoked from network); 20 May 2003 18:11:45 +0200 +Received: from unknown (HELO ??+???) (61.33.134.106) + by ns1.slovanet.net with SMTP; 20 May 2003 18:11:45 +0200 +Received: by london.com (Postfix, from userid 302) + id WTS; Tue, 20 May 2003 20:13:19 +Received: from Œù+⌥ (Œù+⌥ [61.33.134.106]) + by mill.co.uk (Postfix) with ESMTP id 613 + for ; Tue, 20 May 2003 20:13:19 +Subject: Òàìîæåííàî÷èñòêà. ÔèíëäèÌîñêâà. Îò 0,8 çà êã, âêëþ÷àâñå ! 20:13:19 +From: +To: OM3TN +Reply-To: <> +X-Mailer: AOL 7.0 for Windows UK sub 52 +X-Priority: 1 +X-MSMail-Priority: High +Mime-Version: 1.0 +Content-Type: text/html; charset="Windows-1251" +Content-Transfer-Encoding: 7bit +Date: Tue, 20 May 2003 20:13:21 +Message-Id: \ No newline at end of file diff --git a/YAMN/mails/test/readme.txt b/YAMN/mails/test/readme.txt new file mode 100644 index 0000000..35a30b2 --- /dev/null +++ b/YAMN/mails/test/readme.txt @@ -0,0 +1,4 @@ +This is project for testing mime encoding/decoding. It +is very usefull for developers, when some problems with +non-standard headers occured. You can use it to step through +MIME decoding functions. diff --git a/YAMN/mails/test/test.cpp b/YAMN/mails/test/test.cpp new file mode 100644 index 0000000..f8dcd14 --- /dev/null +++ b/YAMN/mails/test/test.cpp @@ -0,0 +1,42 @@ +/* + * This file is for testing purposes. Save in header.txt your problem header and you can + * browse through functions to get result + * + * (c) majvan 2002-2004 + */ + +#include +#include "../m_mails.h" + +extern void WINAPI TranslateHeaderFcn(char *stream,int len,struct CMimeItem **head); +extern void ExtractHeader(struct CMimeItem *items,int CP,struct CHeader *head); + +void main() +{ + char Buffer[8192]; //we do not suppose longer header + FILE *fp; + YAMNMAIL *Mail; + PMAILDATA *MailData; + CMimeItem *head; + + struct CHeader ExtractedHeader; + + if(NULL==(fp=fopen("header2.txt","r"))) + return; + fread(Buffer,sizeof(Buffer),1,fp); + if(ferror(fp)) + { + fclose(fp); + return; + } + fclose(fp); + Mail = new YAMNMAIL; + MailData = new PMAILDATA; + head = new CMimeItem; + Mail->MailData = *MailData; + Mail->MailData->TranslatedHeader = head; + + TranslateHeaderFcn(Buffer,strlen(Buffer), &Mail->MailData->TranslatedHeader); + ExtractHeader(Mail->MailData->TranslatedHeader,CP_ACP,&ExtractedHeader); + return; +} \ No newline at end of file diff --git a/YAMN/mails/test/test.dsp b/YAMN/mails/test/test.dsp new file mode 100644 index 0000000..6d01b36 --- /dev/null +++ b/YAMN/mails/test/test.dsp @@ -0,0 +1,112 @@ +# Microsoft Developer Studio Project File - Name="test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=test - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "test.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "test.mak" CFG="test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "test - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x405 /d "NDEBUG" +# ADD RSC /l 0x405 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "test - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x405 /d "_DEBUG" +# ADD RSC /l 0x405 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "test - Win32 Release" +# Name "test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\decode.cpp +# End Source File +# Begin Source File + +SOURCE=..\mails.cpp +# End Source File +# Begin Source File + +SOURCE=..\mime.cpp +# End Source File +# Begin Source File + +SOURCE=.\test.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/YAMN/mails/test/test.dsw b/YAMN/mails/test/test.dsw new file mode 100644 index 0000000..e25096d --- /dev/null +++ b/YAMN/mails/test/test.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "test"=.\test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + -- cgit v1.2.3