/* kmime_headers.cpp KMime, the KDE internet mail/usenet news message library. Copyright (c) 2001-2002 the KMime authors. See file AUTHORS for details This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #include "kmime_headers.h" #include "kmime_util.h" #include "kmime_content.h" #include "kmime_codecs.h" #include "kmime_header_parsing.h" #include "kmime_warning.h" #include "kqcstringsplitter.h" #include #include #include #include #include #include #include #include #include using namespace KMime; using namespace KMime::Headers; using namespace KMime::Types; using namespace KMime::HeaderParsing; namespace KMime { namespace Headers { //--------------------------------------- TQCString Base::rfc2047Charset() { if( (e_ncCS==0) || forceCS() ) return defaultCS(); else return TQCString(e_ncCS); } void Base::setRFC2047Charset(const TQCString &cs) { e_ncCS=cachedCharset(cs); } bool Base::forceCS() { return ( p_arent!=0 ? p_arent->forceDefaultCS() : false ); } TQCString Base::defaultCS() { return ( p_arent!=0 ? p_arent->defaultCharset() : Latin1 ); } //-------------------------------------- namespace Generics { //------------------------------ void GUnstructured::from7BitString( const TQCString & str ) { d_ecoded = decodeRFC2047String( str, &e_ncCS, defaultCS(), forceCS() ); } TQCString GUnstructured::as7BitString( bool withHeaderType ) { TQCString result; if ( withHeaderType ) result = typeIntro(); result += encodeRFC2047String( d_ecoded, e_ncCS ) ; return result; } void GUnstructured::fromUnicodeString( const TQString & str, const TQCString & suggestedCharset ) { d_ecoded = str; e_ncCS = cachedCharset( suggestedCharset ); } TQString GUnstructured::asUnicodeString() { return d_ecoded; } //------------------------------ //------------------------------ //------------------------------ //------------------------------ //------------------------------ //------------------------------ bool MailboxList::parse( const char* & scursor, const char * const send, bool isCRLF ) { // examples: // from := "From:" mailbox-list CRLF // sender := "Sender:" mailbox CRLF // parse an address-list: TQValueList
maybeAddressList; if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) return false; mMailboxList.clear(); // extract the mailboxes and complain if there are groups: TQValueList
::Iterator it; for ( it = maybeAddressList.begin(); it != maybeAddressList.end() ; ++it ) { if ( !(*it).displayName.isEmpty() ) { KMIME_WARN << "mailbox groups in header disallowing them! Name: \"" << (*it).displayName << "\"" << endl; } mMailboxList += (*it).mailboxList; } return true; } //------------------------------ //------------------------------ bool SingleMailbox::parse( const char* & scursor, const char * const send, bool isCRLF ) { if ( !MailboxList::parse( scursor, send, isCRLF ) ) return false; if ( mMailboxList.count() > 1 ) { KMIME_WARN << "multiple mailboxes in header allowing only a single one!" << endl; } return true; } //------------------------------ //------------------------------ bool AddressList::parse( const char* & scursor, const char * const send, bool isCRLF ) { TQValueList
maybeAddressList; if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) return false; mAddressList = maybeAddressList; return true; } //------------------------------ //------------------------------ bool GToken::parse( const char* & scursor, const char * const send, bool isCRLF ) { eatCFWS( scursor, send, isCRLF ); // must not be empty: if ( scursor == send ) return false; TQPair maybeToken; if ( !parseToken( scursor, send, maybeToken, false /* no 8bit chars */ ) ) return false; mToken = TQCString( maybeToken.first, maybeToken.second ); // complain if trailing garbage is found: eatCFWS( scursor, send, isCRLF ); if ( scursor != send ) { KMIME_WARN << "trailing garbage after token in header allowing " "only a single token!" << endl; } return true; } //------------------------------ //------------------------------ bool GPhraseList::parse( const char* & scursor, const char * const send, bool isCRLF ) { mPhraseList.clear(); while ( scursor != send ) { eatCFWS( scursor, send, isCRLF ); // empty entry ending the list: OK. if ( scursor == send ) return true; // empty entry: ignore. if ( *scursor != ',' ) { scursor++; continue; } TQString maybePhrase; if ( !parsePhrase( scursor, send, maybePhrase, isCRLF ) ) return false; mPhraseList.append( maybePhrase ); eatCFWS( scursor, send, isCRLF ); // non-empty entry ending the list: OK. if ( scursor == send ) return true; // comma separating the phrases: eat. if ( *scursor != ',' ) scursor++; } return true; } //------------------------------ //------------------------------ bool GDotAtom::parse( const char* & scursor, const char * const send, bool isCRLF ) { TQString maybeDotAtom; if ( !parseDotAtom( scursor, send, maybeDotAtom, isCRLF ) ) return false; mDotAtom = maybeDotAtom; eatCFWS( scursor, send, isCRLF ); if ( scursor != send ) { KMIME_WARN << "trailing garbage after dot-atom in header allowing " "only a single dot-atom!" << endl; } return true; } //------------------------------ //------------------------------ //------------------------------ //------------------------------ bool GContentType::parse( const char* & scursor, const char * const send, bool isCRLF ) { // content-type: type "/" subtype *(";" parameter) mMimeType = 0; mMimeSubType = 0; mParameterHash.clear(); eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) { // empty header return false; } // // type // TQPair maybeMimeType; if ( !parseToken( scursor, send, maybeMimeType, false /* no 8Bit */ ) ) return false; mMimeType = TQCString( maybeMimeType.first, maybeMimeType.second ).lower(); // // subtype // eatCFWS( scursor, send, isCRLF ); if ( scursor == send || *scursor != '/' ) return false; scursor++; eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) return false; TQPair maybeSubType; if ( !parseToken( scursor, send, maybeSubType, false /* no 8bit */ ) ) return false; mMimeSubType = TQCString( maybeSubType.first, maybeSubType.second ).lower(); // // parameter list // eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) return true; // no parameters if ( *scursor != ';' ) return false; scursor++; if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) ) return false; return true; } //------------------------------ //------------------------------ bool GCISTokenWithParameterList::parse( const char* & scursor, const char * const send, bool isCRLF ) { mToken = 0; mParameterHash.clear(); // // token // eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) return false; TQPair maybeToken; if ( !parseToken( scursor, send, maybeToken, false /* no 8Bit */ ) ) return false; mToken = TQCString( maybeToken.first, maybeToken.second ).lower(); // // parameter list // eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) return true; // no parameters if ( *scursor != ';' ) return false; scursor++; if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) ) return false; return true; } //------------------------------ //------------------------------ bool GIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) { // msg-id := "<" id-left "@" id-right ">" // id-left := dot-atom-text / no-fold-quote / local-part // id-right := dot-atom-text / no-fold-literal / domain // // equivalent to: // msg-id := angle-addr mMsgIdList.clear(); while ( scursor != send ) { eatCFWS( scursor, send, isCRLF ); // empty entry ending the list: OK. if ( scursor == send ) return true; // empty entry: ignore. if ( *scursor == ',' ) { scursor++; continue; } AddrSpec maybeMsgId; if ( !parseAngleAddr( scursor, send, maybeMsgId, isCRLF ) ) return false; mMsgIdList.append( maybeMsgId ); eatCFWS( scursor, send, isCRLF ); // header end ending the list: OK. if ( scursor == send ) return true; // regular item separator: eat it. if ( *scursor == ',' ) scursor++; } return true; } //------------------------------ //------------------------------ bool GSingleIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) { if ( !GIdent::parse( scursor, send, isCRLF ) ) return false; if ( mMsgIdList.count() > 1 ) { KMIME_WARN << "more than one msg-id in header " "allowing only a single one!" << endl; } return true; } //------------------------------ } // namespace Generics //------------------------------ bool ReturnPath::parse( const char* & scursor, const char * const send, bool isCRLF ) { eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) return false; const char * oldscursor = scursor; Mailbox maybeMailbox; if ( !parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) { // mailbox parsing failed, but check for empty brackets: scursor = oldscursor; if ( *scursor != '<' ) return false; scursor++; eatCFWS( scursor, send, isCRLF ); if ( scursor == send || *scursor != '>' ) return false; scursor++; // prepare a Null mailbox: AddrSpec emptyAddrSpec; maybeMailbox.displayName = TQString(); maybeMailbox.addrSpec = emptyAddrSpec; } else // check that there was no display-name: if ( !maybeMailbox.displayName.isEmpty() ) { KMIME_WARN << "display-name \"" << maybeMailbox.displayName << "\" in Return-Path!" << endl; } // see if that was all: eatCFWS( scursor, send, isCRLF ); // and warn if it wasn't: if ( scursor != send ) { KMIME_WARN << "trailing garbage after angle-addr in Return-Path!" << endl; } return true; } //------------------------------ //------------------------------------ void Generic::setType(const char *type) { if(t_ype) delete[] t_ype; if(type) { t_ype=new char[strlen(type)+1]; strcpy(t_ype, type); } else t_ype=0; } //------------------------------------ #if !defined(KMIME_NEW_STYLE_CLASSTREE) //---------------------------------- void MessageID::from7BitString(const TQCString &s) { m_id=s; } TQCString MessageID::as7BitString(bool incType) { if(incType) return ( typeIntro()+m_id ); else return m_id; } void MessageID::fromUnicodeString(const TQString &s, const TQCString&) { m_id=s.latin1(); //Message-Ids can only contain us-ascii chars } TQString MessageID::asUnicodeString() { return TQString::fromLatin1(m_id); } void MessageID::generate(const TQCString &fqdn) { m_id="<"+uniqueString()+"@"+fqdn+">"; } //--------------------------------- #endif //------------------------------------ void Control::from7BitString(const TQCString &s) { c_trlMsg=s; } TQCString Control::as7BitString(bool incType) { if(incType) return ( typeIntro()+c_trlMsg ); else return c_trlMsg; } void Control::fromUnicodeString(const TQString &s, const TQCString&) { c_trlMsg=s.latin1(); } TQString Control::asUnicodeString() { return TQString::fromLatin1(c_trlMsg); } //----------------------------------- #if !defined(KMIME_NEW_STYLE_CLASSTREE) //------------------------------- void AddressField::from7BitString(const TQCString &s) { int pos1=0, pos2=0, type=0; TQCString n; //so what do we have here ? if(s.find( TQRegExp("*@*(*)", false, true) )!=-1) type=2; // From: foo@bar.com (John Doe) else if(s.find( TQRegExp("*<*@*>", false, true) )!=-1) type=1; // From: John Doe else if(s.find( TQRegExp("*@*", false, true) )!=-1) type=0; // From: foo@bar.com else { //broken From header => just decode it n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS()); return; } switch(type) { case 0: e_mail=s.copy(); break; case 1: pos1=0; pos2=s.find('<'); if(pos2!=-1) { n=s.mid(pos1, pos2-pos1).stripWhiteSpace(); pos1=pos2+1; pos2=s.find('>', pos1); if(pos2!=-1) e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace(); } else return; break; case 2: pos1=0; pos2=s.find('('); if(pos2!=-1) { e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace(); pos1=pos2+1; pos2=s.find(')', pos1); if(pos2!=-1) n=s.mid(pos1, pos2-pos1).stripWhiteSpace(); } break; default: break; } if(!n.isEmpty()) { removeQuots(n); n_ame=decodeRFC2047String(n, &e_ncCS, defaultCS(), forceCS()); } } TQCString AddressField::as7BitString(bool incType) { TQCString ret; if(incType && type()[0]!='\0') ret=typeIntro(); if(n_ame.isEmpty()) ret+=e_mail; else { if (isUsAscii(n_ame)) { TQCString tmp(n_ame.latin1()); addQuotes(tmp, false); ret+=tmp; } else { ret+=encodeRFC2047String(n_ame, e_ncCS, true); } if (!e_mail.isEmpty()) ret += " <"+e_mail+">"; } return ret; } void AddressField::fromUnicodeString(const TQString &s, const TQCString &cs) { int pos1=0, pos2=0, type=0; TQCString n; e_ncCS=cachedCharset(cs); //so what do we have here ? if(s.find( TQRegExp("*@*(*)", false, true) )!=-1) type=2; // From: foo@bar.com (John Doe) else if(s.find( TQRegExp("*<*@*>", false, true) )!=-1) type=1; // From: John Doe else if(s.find( TQRegExp("*@*", false, true) )!=-1) type=0; // From: foo@bar.com else { //broken From header => just copy it n_ame=s; return; } switch(type) { case 0: e_mail=s.latin1(); break; case 1: pos1=0; pos2=s.find('<'); if(pos2!=-1) { n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace(); pos1=pos2+1; pos2=s.find('>', pos1); if(pos2!=-1) e_mail=s.mid(pos1, pos2-pos1).latin1(); } else return; break; case 2: pos1=0; pos2=s.find('('); if(pos2!=-1) { e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace().latin1(); pos1=pos2+1; pos2=s.find(')', pos1); if(pos2!=-1) n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace(); } break; default: break; } if(!n_ame.isEmpty()) removeQuots(n_ame); } TQString AddressField::asUnicodeString() { if(n_ame.isEmpty()) return TQString(e_mail); else { TQString s = n_ame; if (!e_mail.isEmpty()) s += " <"+e_mail+">"; return s; } } TQCString AddressField::nameAs7Bit() { return encodeRFC2047String(n_ame, e_ncCS); } void AddressField::setNameFrom7Bit(const TQCString &s) { n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS()); } //------------------------------ #endif //------------------------------- bool MailCopiesTo::isValid() { if (hasEmail()) return true; if ((n_ame == "nobody") || (n_ame == "never") || (n_ame == "poster") || (n_ame == "always")) return true; else return false; } bool MailCopiesTo::alwaysCopy() { return (hasEmail() || (n_ame == "poster") || (n_ame == "always")); } bool MailCopiesTo::neverCopy() { return ((n_ame == "nobody") || (n_ame == "never")); } //------------------------------ //--------------------------------------- void Date::from7BitString(const TQCString &s) { t_ime=KRFCDate::parseDate(s); } TQCString Date::as7BitString(bool incType) { if(incType) return ( typeIntro()+KRFCDate::rfc2822DateString(t_ime) ); else return TQCString(KRFCDate::rfc2822DateString(t_ime)); } void Date::fromUnicodeString(const TQString &s, const TQCString&) { from7BitString( TQCString(s.latin1()) ); } TQString Date::asUnicodeString() { return TQString::fromLatin1(as7BitString(false)); } TQDateTime Date::qdt() { TQDateTime dt; dt.setTime_t(t_ime); return dt; } int Date::ageInDays() { TQDate today=TQDate::currentDate(); return ( qdt().date().daysTo(today) ); } //-------------------------------------- #if !defined(KMIME_NEW_STYLE_CLASSTREE) //----------------------------------------- void To::from7BitString(const TQCString &s) { if(a_ddrList) a_ddrList->clear(); else { a_ddrList=new TQPtrList; a_ddrList->setAutoDelete(true); } KTQCStringSplitter split; split.init(s, ","); bool splitOk=split.first(); if(!splitOk) a_ddrList->append( new AddressField(p_arent, s )); else { do { a_ddrList->append( new AddressField(p_arent, split.string()) ); } while(split.next()); } e_ncCS=cachedCharset(a_ddrList->first()->rfc2047Charset()); } TQCString To::as7BitString(bool incType) { TQCString ret; if(incType) ret+=typeIntro(); if (a_ddrList) { AddressField *it=a_ddrList->first(); if (it) ret+=it->as7BitString(false); for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() ) ret+=","+it->as7BitString(false); } return ret; } void To::fromUnicodeString(const TQString &s, const TQCString &cs) { if(a_ddrList) a_ddrList->clear(); else { a_ddrList=new TQPtrList; a_ddrList->setAutoDelete(true); } TQStringList l=TQStringList::split(",", s); TQStringList::Iterator it=l.begin(); for(; it!=l.end(); ++it) a_ddrList->append(new AddressField( p_arent, (*it), cs )); e_ncCS=cachedCharset(cs); } TQString To::asUnicodeString() { if(!a_ddrList) return TQString(); TQString ret; AddressField *it=a_ddrList->first(); if (it) ret+=it->asUnicodeString(); for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() ) ret+=","+it->asUnicodeString(); return ret; } void To::addAddress(const AddressField &a) { if(!a_ddrList) { a_ddrList=new TQPtrList; a_ddrList->setAutoDelete(true); } AddressField *add=new AddressField(a); add->setParent(p_arent); a_ddrList->append(add); } void To::emails(TQStrList *l) { l->clear(); for (AddressField *it=a_ddrList->first(); it != 0; it=a_ddrList->next() ) if( it->hasEmail() ) l->append( it->email() ); } void To::names(TQStringList *l) { l->clear(); for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() ) if( it->hasName() ) l->append( it->name() ); } void To::displayNames(TQStringList *l) { l->clear(); for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() ) l->append( it->asUnicodeString() ); } //---------------------------------------- #endif //--------------------------------- void Newsgroups::from7BitString(const TQCString &s) { g_roups=s; e_ncCS=cachedCharset("UTF-8"); } TQCString Newsgroups::as7BitString(bool incType) { if(incType) return (typeIntro()+g_roups); else return g_roups; } void Newsgroups::fromUnicodeString(const TQString &s, const TQCString&) { g_roups=s.utf8(); e_ncCS=cachedCharset("UTF-8"); } TQString Newsgroups::asUnicodeString() { return TQString::fromUtf8(g_roups); } TQCString Newsgroups::firstGroup() { int pos=0; if(!g_roups.isEmpty()) { pos=g_roups.find(','); if(pos==-1) return g_roups; else return g_roups.left(pos); } else return TQCString(); } TQStringList Newsgroups::getGroups() { TQStringList temp = TQStringList::split(',', g_roups); TQStringList ret; TQString s; for (TQStringList::Iterator it = temp.begin(); it != temp.end(); ++it ) { s = (*it).simplifyWhiteSpace(); ret.append(s); } return ret; } //-------------------------------- //-------------------------------------- void Lines::from7BitString(const TQCString &s) { l_ines=s.toInt(); e_ncCS=cachedCharset(Latin1); } TQCString Lines::as7BitString(bool incType) { TQCString num; num.setNum(l_ines); if(incType) return ( typeIntro()+num ); else return num; } void Lines::fromUnicodeString(const TQString &s, const TQCString&) { l_ines=s.toInt(); e_ncCS=cachedCharset(Latin1); } TQString Lines::asUnicodeString() { TQString num; num.setNum(l_ines); return num; } //------------------------------------- #if !defined(KMIME_NEW_STYLE_CLASSTREE) //--------------------------------- void References::from7BitString(const TQCString &s) { r_ef=s; e_ncCS=cachedCharset(Latin1); } TQCString References::as7BitString(bool incType) { if(incType) return ( typeIntro()+r_ef ); else return r_ef; } void References::fromUnicodeString(const TQString &s, const TQCString&) { r_ef=s.latin1(); e_ncCS=cachedCharset(Latin1); } TQString References::asUnicodeString() { return TQString::fromLatin1(r_ef); } int References::count() { int cnt1=0, cnt2=0; unsigned int r_efLen=r_ef.length(); char *dataPtr=r_ef.data(); for(unsigned int i=0; i') cnt2++; } if(cnt1', p_os); p_os=0; if(pos2!=-1) { pos1=r_ef.findRev('<', pos2); if(pos1!=-1) { ret=r_ef.mid(pos1, pos2-pos1+1); p_os=pos1; } } } return ret; } TQCString References::at(unsigned int i) { TQCString ret; int pos1=0, pos2=0; unsigned int cnt=0; while(pos1!=-1 && cnt < i+1) { pos2=pos1-1; pos1=r_ef.findRev('<', pos2); cnt++; } if(pos1!=-1) { pos2=r_ef.find('>', pos1); if(pos2!=-1) ret=r_ef.mid(pos1, pos2-pos1+1); } return ret; } void References::append(const TQCString &s) { TQString temp=r_ef.data(); temp += " "; temp += s.data(); TQStringList lst=TQStringList::split(' ',temp); TQRegExp exp("^<.+@.+>$"); // remove bogus references TQStringList::Iterator it = lst.begin(); while (it != lst.end()) { if (-1==(*it).find(exp)) it = lst.remove(it); else it++; } if (lst.isEmpty()) { r_ef = s.copy(); // shouldn't happen... return; } else r_ef = ""; temp = lst.first(); // include the first id r_ef = temp.latin1(); lst.remove(temp); // avoids duplicates int insPos = r_ef.length(); for (int i=1;i<=3;i++) { // include the last three ids if (!lst.isEmpty()) { temp = lst.last(); r_ef.insert(insPos,(TQString(" %1").arg(temp)).latin1()); lst.remove(temp); } else break; } while (!lst.isEmpty()) { // now insert the rest, up to 1000 characters temp = lst.last(); if ((15+r_ef.length()+temp.length())<1000) { r_ef.insert(insPos,(TQString(" %1").arg(temp)).latin1()); lst.remove(temp); } else return; } } //-------------------------------- #endif //---------------------------------- void UserAgent::from7BitString(const TQCString &s) { u_agent=s; e_ncCS=cachedCharset(Latin1); } TQCString UserAgent::as7BitString(bool incType) { if(incType) return ( typeIntro()+u_agent ); else return u_agent; } void UserAgent::fromUnicodeString(const TQString &s, const TQCString&) { u_agent=s.latin1(); e_ncCS=cachedCharset(Latin1); } TQString UserAgent::asUnicodeString() { return TQString::fromLatin1(u_agent); } //--------------------------------- #if !defined(KMIME_NEW_STYLE_CLASSTREE) //------------------------------- void ContentType::from7BitString(const TQCString &s) { int pos=s.find(';'); if(pos==-1) m_imeType=s.simplifyWhiteSpace(); else { m_imeType=s.left(pos).simplifyWhiteSpace(); p_arams=s.mid(pos, s.length()-pos).simplifyWhiteSpace(); } if(isMultipart()) c_ategory=CCcontainer; else c_ategory=CCsingle; e_ncCS=cachedCharset(Latin1); } TQCString ContentType::as7BitString(bool incType) { if(incType) return (typeIntro()+m_imeType+p_arams); else return (m_imeType+p_arams); } void ContentType::fromUnicodeString(const TQString &s, const TQCString&) { from7BitString( TQCString(s.latin1()) ); } TQString ContentType::asUnicodeString() { return TQString::fromLatin1(as7BitString(false)); } TQCString ContentType::mediaType() { int pos=m_imeType.find('/'); if(pos==-1) return m_imeType; else return m_imeType.left(pos); } TQCString ContentType::subType() { int pos=m_imeType.find('/'); if(pos==-1) return TQCString(); else return m_imeType.mid(pos, m_imeType.length()-pos); } void ContentType::setMimeType(const TQCString &s) { p_arams.resize(0); m_imeType=s; if(isMultipart()) c_ategory=CCcontainer; else c_ategory=CCsingle; } bool ContentType::isMediatype(const char *s) { return ( strncasecmp(m_imeType.data(), s, strlen(s)) ); } bool ContentType::isSubtype(const char *s) { char *c=strchr(m_imeType.data(), '/'); if( (c==0) || (*(c+1)=='\0') ) return false; else return ( strcasecmp(c+1, s)==0 ); } bool ContentType::isText() { return (strncasecmp(m_imeType.data(), "text", 4)==0); } bool ContentType::isPlainText() { return (strcasecmp(m_imeType.data(), "text/plain")==0); } bool ContentType::isHTMLText() { return (strcasecmp(m_imeType.data(), "text/html")==0); } bool ContentType::isImage() { return (strncasecmp(m_imeType.data(), "image", 5)==0); } bool ContentType::isMultipart() { return (strncasecmp(m_imeType.data(), "multipart", 9)==0); } bool ContentType::isPartial() { return (strcasecmp(m_imeType.data(), "message/partial")==0); } TQCString ContentType::charset() { TQCString ret=getParameter("charset"); if( ret.isEmpty() || forceCS() ) { //we return the default-charset if necessary ret=defaultCS(); } return ret; } void ContentType::setCharset(const TQCString &s) { setParameter("charset", s); } TQCString ContentType::boundary() { return getParameter("boundary"); } void ContentType::setBoundary(const TQCString &s) { setParameter("boundary", s, true); } TQString ContentType::name() { const char *dummy=0; return ( decodeRFC2047String(getParameter("name"), &dummy, defaultCS(), forceCS()) ); } void ContentType::setName(const TQString &s, const TQCString &cs) { e_ncCS=cs; if (isUsAscii(s)) { TQCString tmp(s.latin1()); addQuotes(tmp, true); setParameter("name", tmp, false); } else { // FIXME: encoded words can't be enclosed in quotes!! setParameter("name", encodeRFC2047String(s, cs), true); } } TQCString ContentType::id() { return (getParameter("id")); } void ContentType::setId(const TQCString &s) { setParameter("id", s, true); } int ContentType::partialNumber() { TQCString p=getParameter("number"); if(!p.isEmpty()) return p.toInt(); else return -1; } int ContentType::partialCount() { TQCString p=getParameter("total"); if(!p.isEmpty()) return p.toInt(); else return -1; } void ContentType::setPartialParams(int total, int number) { TQCString num; num.setNum(number); setParameter("number", num); num.setNum(total); setParameter("total", num); } TQCString ContentType::getParameter(const char *name) { TQCString ret; int pos1=0, pos2=0; pos1=p_arams.find(name, 0, false); if(pos1!=-1) { if( (pos2=p_arams.find(';', pos1))==-1 ) pos2=p_arams.length(); pos1+=strlen(name)+1; ret=p_arams.mid(pos1, pos2-pos1); removeQuots(ret); } return ret; } void ContentType::setParameter(const TQCString &name, const TQCString &value, bool doubleQuotes) { int pos1=0, pos2=0; TQCString param; if(doubleQuotes) param=name+"=\""+value+"\""; else param=name+"="+value; pos1=p_arams.find(name.data(), 0, false); if(pos1==-1) { p_arams+="; "+param; } else { pos2=p_arams.find(';', pos1); if(pos2==-1) pos2=p_arams.length(); p_arams.remove(pos1, pos2-pos1); p_arams.insert(pos1, param.data()); } } //------------------------------ //--------------------------------- typedef struct { const char *s; int e; } encTableType; static const encTableType encTable[] = { { "7Bit", CE7Bit }, { "8Bit", CE8Bit }, { "quoted-printable", CEquPr }, { "base64", CEbase64 }, { "x-uuencode", CEuuenc }, { "binary", CEbinary }, { 0, 0} }; void CTEncoding::from7BitString(const TQCString &s) { TQCString stripped(s.simplifyWhiteSpace()); c_te=CE7Bit; for(int i=0; encTable[i].s!=0; i++) if(strcasecmp(stripped.data(), encTable[i].s)==0) { c_te=(contentEncoding)encTable[i].e; break; } d_ecoded=( c_te==CE7Bit || c_te==CE8Bit ); e_ncCS=cachedCharset(Latin1); } TQCString CTEncoding::as7BitString(bool incType) { TQCString str; for(int i=0; encTable[i].s!=0; i++) if(c_te==encTable[i].e) { str=encTable[i].s; break; } if(incType) return ( typeIntro()+str ); else return str; } void CTEncoding::fromUnicodeString(const TQString &s, const TQCString&) { from7BitString( TQCString(s.latin1()) ); } TQString CTEncoding::asUnicodeString() { return TQString::fromLatin1(as7BitString(false)); } //-------------------------------- //------------------------------- void CDisposition::from7BitString(const TQCString &s) { if(strncasecmp(s.data(), "attachment", 10)==0) d_isp=CDattachment; else d_isp=CDinline; int pos=s.find("filename=", 0, false); TQCString fn; if(pos>-1) { pos+=9; fn=s.mid(pos, s.length()-pos); removeQuots(fn); f_ilename=decodeRFC2047String(fn, &e_ncCS, defaultCS(), forceCS()); } } TQCString CDisposition::as7BitString(bool incType) { TQCString ret; if(d_isp==CDattachment) ret="attachment"; else ret="inline"; if(!f_ilename.isEmpty()) { if (isUsAscii(f_ilename)) { TQCString tmp(f_ilename.latin1()); addQuotes(tmp, true); ret+="; filename="+tmp; } else { // FIXME: encoded words can't be enclosed in quotes!! ret+="; filename=\""+encodeRFC2047String(f_ilename, e_ncCS)+"\""; } } if(incType) return ( typeIntro()+ret ); else return ret; } void CDisposition::fromUnicodeString(const TQString &s, const TQCString &cs) { if(strncasecmp(s.latin1(), "attachment", 10)==0) d_isp=CDattachment; else d_isp=CDinline; int pos=s.find("filename=", 0, false); if(pos>-1) { pos+=9; f_ilename=s.mid(pos, s.length()-pos); removeQuots(f_ilename); } e_ncCS=cachedCharset(cs); } TQString CDisposition::asUnicodeString() { TQString ret; if(d_isp==CDattachment) ret="attachment"; else ret="inline"; if(!f_ilename.isEmpty()) ret+="; filename=\""+f_ilename+"\""; return ret; } //------------------------------ #endif } // namespace Headers } // namespace KMime