/* * This code implements retrieving info from MIME header * * (c) majvan 2002-2004 */ #include "../stdafx.h" //-------------------------------------------------------------------------------------------------- //Copies one string to another // srcstart- source string // srcend- address to the end of source string // dest- pointer that stores new allocated string that contains copy of source string // mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' characters (or '<' and '>') if they are at start and end of source string void CopyToHeader(char *srcstart,char *srcend,char **dest,int mode); //Extracts email address (finds nick name and mail and then stores them to strings) // finder- source string // storeto- pointer that receives address of mail string // storetonick- pointer that receives address of nickname void ExtractAddressFromLine(char *finder,char **storeto,char **storetonick); //Extracts simple text from string // finder- source string // storeto- pointer that receives address of string void ExtractStringFromLine(char *finder,char **storeto); //Extracts some item from content-type string //Example: ContentType string: "TEXT/PLAIN; charset=US-ASCII", item:"charset=", returns: "US-ASCII" // ContetType- content-type string // value- string item // returns extracted string (or NULL when not found) char *ExtractFromContentType(char *ContentType,char *value); //Extracts info from header text into header members //Note that this function as well as struct CShortHeadwer can be always changed, because there are many items to extract //(e.g. the X-Priority and Importance and so on) // items- translated header (see TranslateHeaderFcn) // head- header to be filled with values extracted from items void ExtractShortHeader(struct CMimeItem *items,struct CShortHeader *head); //Extracts header to mail using ExtractShortHeader fcn. // items- translated header (see TranslateHeaderFcn) // CP- codepage used when no default found // head- header to be filled with values extracted from items, in unicode (wide char) void ExtractHeader(struct CMimeItem *items,int &CP,struct CHeader *head); //Deletes items in CShortHeader structure // head- structure whose items are deleted void DeleteShortHeaderContent(struct CShortHeader *head); //Deletes list of YAMN_MIMENAMES structures // Names- pointer to first item of list void DeleteNames(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==nullptr) return; if (srcstart>=srcend) return; if ((mode==MIME_MAIL) && (((*srcstart=='"') && (*(srcend-1)=='"')) || ((*srcstart=='<') && (*(srcend-1)=='>')))) { srcstart++; srcend--; } if (srcstart>=srcend) return; if (nullptr != *dest) delete[] *dest; if (nullptr==(*dest=new char[srcend-srcstart+1])) return; dst=*dest; for (;srcstart' at the end of line CopyToHeader(finder,finderend+1,storeto,MIME_MAIL); else //at the end of line, there's '>' { char *finder2=finderend; while((*finder2 != '<') && (finder2>finder)) finder2--; //go to matching '<' or to the start CopyToHeader(finder2,finderend+1,storeto,MIME_MAIL); if (*finder2=='<') //if we found '<', the rest copy as from nick { finder2--; while(WS(finder2) || ENDLINE(finder2)) finder2--; //parse whitespace CopyToHeader(finder,finder2+1,storetonick,MIME_MAIL); //and store nickname } } } else { char *finderend=finder+1; do { if (ENDLINEWS(finderend)) //after endline information continues finderend+=2; while(!ENDLINE(finderend) && (*finderend != '>') && !EOS(finderend)) finderend++; //seek to the matching < or to the end of line or to the end of string }while(ENDLINEWS(finderend)); CopyToHeader(finder,finderend+1,storeto,MIME_MAIL); //go to first '>' or to the end and copy finder=finderend+1; while(WS(finder)) finder++; //parse whitespace if (!ENDLINE(finder) && !EOS(finder)) //if there are chars yet, it's nick { finderend=finder+1; while(!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string finderend--; while(WS(finderend)) finderend--; //find the end of line, no whitespace CopyToHeader(finder,finderend+1,storetonick,MIME_MAIL); } } } void ExtractStringFromLine(char *finder,char **storeto) { if (finder==nullptr) { *storeto=nullptr; return; } while(WS(finder)) finder++; char *finderend=finder; do { if (ENDLINEWS(finderend)) finderend++; //after endline information continues while(!ENDLINE(finderend) && !EOS(finderend)) finderend++; }while(ENDLINEWS(finderend)); finderend--; while(WS(finderend)) finderend--; //find the end of line, no whitespace CopyToHeader(finder,finderend+1,storeto,MIME_PLAIN); } char *ExtractFromContentType(char *ContentType,char *value) { char *lowered = _strdup(ContentType); ToLower(lowered); char *finder=strstr(lowered,value); if (finder==nullptr) { free (lowered); return nullptr; } finder = finder-lowered+ContentType; free (lowered); char *temp,*copier; char *CopiedString; temp=finder-1; while((temp>ContentType) && WS(temp)) temp--; //now we have to find, if the word "Charset=" is located after ';' like "; Charset=" if (*temp != ';' && !ENDLINE(temp) && temp != ContentType) return nullptr; finder=finder+mir_strlen(value); //jump over value string while(WS(finder)) finder++; //jump over whitespaces temp=finder; while(*temp != 0 && *temp != ';') temp++; //jump to the end of setting (to the next ;) temp--; while(WS(temp)) temp--; //remove whitespaces from the end if (*finder=='\"') { //remove heading and tailing quotes finder++; if (*temp=='\"') temp--; } if (nullptr==(CopiedString=new char[++temp-finder+1])) return nullptr; for (copier=CopiedString;finder != temp;*copier++=*finder++); //copy string *copier=0; //and end it with zero character return CopiedString; } void ExtractShortHeader(struct CMimeItem *items,struct CShortHeader *head) { for (;items != nullptr;items=items->Next) { //at the start of line //MessageBox(NULL,items->value,items->name,0); if (0==_strnicmp(items->name,"From",4)) { if (items->value==nullptr) continue; #ifdef DEBUG_DECODE DebugLog(DecodeFile,""); #endif ExtractAddressFromLine(items->value,&head->From,&head->FromNick); #ifdef DEBUG_DECODE DebugLog(DecodeFile,"\n"); #endif } else if (0==_strnicmp(items->name,"Return-Path",11)) { if (items->value==nullptr) continue; #ifdef DEBUG_DECODE DebugLog(DecodeFile,""); #endif ExtractAddressFromLine(items->value,&head->ReturnPath,&head->ReturnPathNick); #ifdef DEBUG_DECODE DebugLog(DecodeFile,"\n"); #endif } else if (0==_strnicmp(items->name,"Subject",7)) { if (items->value==nullptr) continue; #ifdef DEBUG_DECODE DebugLog(DecodeFile,""); #endif ExtractStringFromLine(items->value,&head->Subject); #ifdef DEBUG_DECODE DebugLog(DecodeFile,"\n"); #endif } else if (0==_strnicmp(items->name,"Body",4)) { if (items->value==nullptr) continue; #ifdef DEBUG_DECODE DebugLog(DecodeFile,""); #endif ExtractStringFromLine(items->value,&head->Body); #ifdef DEBUG_DECODE DebugLog(DecodeFile,"\n"); #endif } else if (0==_strnicmp(items->name,"Date",4)) { if (items->value==nullptr) continue; #ifdef DEBUG_DECODE DebugLog(DecodeFile,""); #endif ExtractStringFromLine(items->value,&head->Date); #ifdef DEBUG_DECODE DebugLog(DecodeFile,"\n"); #endif } else if (0==_strnicmp(items->name,"Content-Type",12)) { if (items->value==nullptr) continue; char *ContentType=nullptr,*CharSetStr; #ifdef DEBUG_DECODE DebugLog(DecodeFile,""); #endif ExtractStringFromLine(items->value,&ContentType); #ifdef DEBUG_DECODE DebugLog(DecodeFile,"\n"); #endif ToLower(ContentType); if (nullptr != (CharSetStr=ExtractFromContentType(ContentType,"charset="))) { head->CP=GetCharsetFromString(CharSetStr,mir_strlen(CharSetStr)); delete[] CharSetStr; } delete[] ContentType; } else if (0==_strnicmp(items->name,"Importance",10)) { if (items->value==nullptr) continue; #ifdef DEBUG_DECODE DebugLog(DecodeFile,""); #endif if (head->Priority != -1) { if (0==strncmp(items->value,"low",3)) head->Priority=5; else if (0==strncmp(items->value,"normal",6)) head->Priority=3; else if (0==strncmp(items->value,"high",4)) head->Priority=1; } #ifdef DEBUG_DECODE DebugLog(DecodeFile,"\n"); #endif } else if (0==_strnicmp(items->name,"X-Priority",10)) { if (items->value==nullptr) continue; #ifdef DEBUG_DECODE DebugLog(DecodeFile,""); #endif if ((*items->value>='1') && (*items->value<='5')) head->Priority=*items->value-'0'; #ifdef DEBUG_DECODE DebugLog(DecodeFile,"\n"); #endif } } } void ExtractHeader(struct CMimeItem *items,int &CP,struct CHeader *head) { struct CShortHeader ShortHeader; memset(&ShortHeader, 0, sizeof(struct CShortHeader)); ShortHeader.Priority=ShortHeader.CP=-1; #ifdef DEBUG_DECODE DebugLog(DecodeFile,"\n"); #endif ExtractShortHeader(items,&ShortHeader); head->Priority=ShortHeader.Priority==-1 ? 3 : ShortHeader.Priority; CP=ShortHeader.CP==-1 ? CP : ShortHeader.CP; #ifdef DEBUG_DECODE if (NULL != ShortHeader.From) DebugLog(DecodeFile,"%s%s%s%s%s%s\n"); DebugLog(DecodeFile,"\n"); #endif ConvertCodedStringToUnicode(ShortHeader.From,&head->From,CP,MIME_PLAIN); #ifdef DEBUG_DECODE if (NULL != head->From) DebugLogW(DecodeFile,L"%s\n",head->From); #endif ConvertCodedStringToUnicode(ShortHeader.FromNick,&head->FromNick,CP,MIME_MAIL); #ifdef DEBUG_DECODE if (NULL != head->FromNick) DebugLogW(DecodeFile,L"%s\n",head->FromNick); #endif ConvertCodedStringToUnicode(ShortHeader.ReturnPath,&head->ReturnPath,CP,MIME_PLAIN); #ifdef DEBUG_DECODE if (NULL != head->ReturnPath) DebugLogW(DecodeFile,L"%s\n",head->ReturnPath); #endif ConvertCodedStringToUnicode(ShortHeader.ReturnPathNick,&head->ReturnPathNick,CP,MIME_MAIL); #ifdef DEBUG_DECODE if (NULL != head->ReturnPathNick) DebugLogW(DecodeFile,L"%s\n",head->ReturnPathNick); #endif ConvertCodedStringToUnicode(ShortHeader.Subject,&head->Subject,CP,MIME_PLAIN); #ifdef DEBUG_DECODE if (NULL != head->Subject) DebugLogW(DecodeFile,L"%s\n",head->Subject); #endif ConvertCodedStringToUnicode(ShortHeader.Date,&head->Date,CP,MIME_PLAIN); #ifdef DEBUG_DECODE if (NULL != head->Date) DebugLogW(DecodeFile,L"%s\n",head->Date); #endif ConvertCodedStringToUnicode(ShortHeader.Body,&head->Body,CP,MIME_PLAIN); #ifdef DEBUG_DECODE if (NULL != head->Body) DebugLogW(DecodeFile,L"%s\n",head->Body); #endif #ifdef DEBUG_DECODE DebugLog(DecodeFile,"\n"); #endif DeleteShortHeaderContent(&ShortHeader); // head->From=L"Frommmm"; // head->Subject=L"Subject"; return; } void DeleteShortHeaderContent(struct CShortHeader *head) { if (head->From != nullptr) delete[] head->From; if (head->FromNick != nullptr) delete[] head->FromNick; if (head->ReturnPath != nullptr) delete[] head->ReturnPath; if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick; if (head->Subject != nullptr) delete[] head->Subject; if (head->Date != nullptr) delete[] head->Date; if (head->To != nullptr) DeleteShortNames(head->To); if (head->Cc != nullptr) DeleteShortNames(head->Cc); if (head->Bcc != nullptr) DeleteShortNames(head->Bcc); if (head->Body != nullptr) delete[] head->Body; } void DeleteHeaderContent(struct CHeader *head) { if (head->From != nullptr) delete[] head->From; if (head->FromNick != nullptr) delete[] head->FromNick; if (head->ReturnPath != nullptr) delete[] head->ReturnPath; if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick; if (head->Subject != nullptr) delete[] head->Subject; if (head->Date != nullptr) delete[] head->Date; if (head->Body != nullptr) delete[] head->Body; if (head->To != nullptr) DeleteNames(head->To); if (head->Cc != nullptr) DeleteNames(head->Cc); if (head->Bcc != nullptr) DeleteNames(head->Bcc); } void DeleteNames(PYAMN_MIMENAMES Names) { PYAMN_MIMENAMES Parser=Names,Old; for (;Parser != nullptr;Parser=Parser->Next) { if (Parser->Value != nullptr) delete[] Parser->Value; if (Parser->ValueNick != nullptr) delete[] Parser->ValueNick; Old=Parser; Parser=Parser->Next; delete Old; } } void DeleteShortNames(PYAMN_MIMESHORTNAMES Names) { PYAMN_MIMESHORTNAMES Parser=Names,Old; for (;Parser != nullptr;Parser=Parser->Next) { if (Parser->Value != nullptr) delete[] Parser->Value; if (Parser->ValueNick != nullptr) 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 = mir_strlen(data->Src); try { char *finder=data->Src; char *prev1,*prev2,*prev3; while(finder<=(data->Src+len)) { while(ENDLINEWS(finder)) finder++; //at the start of line if (finder>data->Src) { if (*(finder-2)=='\r' || *(finder-2)=='\n') *(finder-2)=0; if (*(finder-1)=='\r' || *(finder-1)=='\n') *(finder-1)=0; } prev1=finder; while(*finder != ':' && !EOS(finder) && !ENDLINE(finder)) finder++; if (ENDLINE(finder)||EOS(finder)) { // no ":" in the line? here the body begins; data->body = prev1; break; } prev2=finder++; while(WS(finder) && !EOS(finder)) finder++; if (!EOS(finder)) prev3=finder; else break; do { if (ENDLINEWS(finder)) finder+=2; //after endline information continues while(!ENDLINE(finder) && !EOS(finder)) finder++; }while(ENDLINEWS(finder)); if (!_strnicmp(prev1,"Content-type",prev2-prev1)) { data->ContType = prev3; } else if (!_strnicmp(prev1,"Content-Transfer-Encoding",prev2-prev1)) { data->TransEnc = prev3; } if (EOS(finder)) break; finder++; if (ENDLINE(finder)) { finder++; if (ENDLINE(finder)) { // end of headers. message body begins if (finder>data->Src) { if (*(finder-2)=='\r' || *(finder-2)=='\n') *(finder-2)=0; if (*(finder-1)=='\r' || *(finder-1)=='\n') *(finder-1)=0; } finder++; if (ENDLINE(finder))finder++; prev1 = finder; while (!EOS(finder+1))finder++; if (ENDLINE(finder))finder--; prev2 = finder; if (prev2>prev1) { // yes, we have body data->body = prev1; } break; // there is nothing else } } } } catch(...) { MessageBox(nullptr, TranslateT("Translate header error"), L"", 0); } if (data->body) data->bodyLen = (int)mir_strlen(data->body); } //from decode.cpp int DecodeQuotedPrintable(char *Src,char *Dst,int DstLen, BOOL isQ); int DecodeBase64(char *Src,char *Dst,int DstLen); int ConvertStringToUnicode(char *stream,unsigned int cp,WCHAR **out); WCHAR *ParseMultipartBody(char *src, char *bond) { char *srcback = _strdup(src); size_t sizebond = mir_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