diff options
Diffstat (limited to 'libkmime/kmime_headers.cpp')
-rw-r--r-- | libkmime/kmime_headers.cpp | 1634 |
1 files changed, 1634 insertions, 0 deletions
diff --git a/libkmime/kmime_headers.cpp b/libkmime/kmime_headers.cpp new file mode 100644 index 000000000..7ae5b95bf --- /dev/null +++ b/libkmime/kmime_headers.cpp @@ -0,0 +1,1634 @@ +/* + 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 <qtextcodec.h> +#include <qstring.h> +#include <qcstring.h> +#include <qstringlist.h> +#include <qvaluelist.h> + +#include <kglobal.h> +#include <kcharsets.h> +#include <krfcdate.h> + +#include <assert.h> + + +using namespace KMime; +using namespace KMime::Headers; +using namespace KMime::Types; +using namespace KMime::HeaderParsing; + +namespace KMime { +namespace Headers { +//-----<Base>---------------------------------- + +QCString Base::rfc2047Charset() +{ + if( (e_ncCS==0) || forceCS() ) + return defaultCS(); + else + return QCString(e_ncCS); +} + + +void Base::setRFC2047Charset(const QCString &cs) +{ + e_ncCS=cachedCharset(cs); +} + + +bool Base::forceCS() +{ + return ( p_arent!=0 ? p_arent->forceDefaultCS() : false ); +} + + +QCString Base::defaultCS() +{ + return ( p_arent!=0 ? p_arent->defaultCharset() : Latin1 ); +} + + +//-----</Base>--------------------------------- + +namespace Generics { + +//-----<GUnstructured>------------------------- + +void GUnstructured::from7BitString( const QCString & str ) +{ + d_ecoded = decodeRFC2047String( str, &e_ncCS, defaultCS(), forceCS() ); +} + +QCString GUnstructured::as7BitString( bool withHeaderType ) +{ + QCString result; + if ( withHeaderType ) + result = typeIntro(); + result += encodeRFC2047String( d_ecoded, e_ncCS ) ; + + return result; +} + +void GUnstructured::fromUnicodeString( const QString & str, + const QCString & suggestedCharset ) +{ + d_ecoded = str; + e_ncCS = cachedCharset( suggestedCharset ); +} + +QString GUnstructured::asUnicodeString() +{ + return d_ecoded; +} + +//-----</GUnstructured>------------------------- + + + +//-----<GStructured>------------------------- + +//-----</GStructured>------------------------- + + + + +//-----<GAddress>------------------------- + + +//-----</GAddress>------------------------- + + + +//-----<MailboxList>------------------------- + +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: + QValueList<Address> maybeAddressList; + if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) + return false; + + mMailboxList.clear(); + + // extract the mailboxes and complain if there are groups: + QValueList<Address>::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; +} + +//-----</MailboxList>------------------------- + + + +//-----<SingleMailbox>------------------------- + +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; +} + +//-----</SingleMailbox>------------------------- + + + +//-----<AddressList>------------------------- + +bool AddressList::parse( const char* & scursor, const char * const send, + bool isCRLF ) { + + QValueList<Address> maybeAddressList; + if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) + return false; + + mAddressList = maybeAddressList; + return true; +} + +//-----</AddressList>------------------------- + + + +//-----<GToken>------------------------- + +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; + + QPair<const char*,int> maybeToken; + if ( !parseToken( scursor, send, maybeToken, false /* no 8bit chars */ ) ) + return false; + mToken = QCString( 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; +} + +//-----</GToken>------------------------- + + + +//-----<GPhraseList>------------------------- + +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; } + + QString 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; +} + +//-----</GPhraseList>------------------------- + + + +//-----<GDotAtom>------------------------- + +bool GDotAtom::parse( const char* & scursor, const char * const send, + bool isCRLF ) { + + QString 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; +} + +//-----</GDotAtom>------------------------- + + + +//-----<GParametrized>------------------------- + +//-----</GParametrized>------------------------- + + + + +//-----</GContentType>------------------------- + +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 + // + + QPair<const char*,int> maybeMimeType; + if ( !parseToken( scursor, send, maybeMimeType, false /* no 8Bit */ ) ) + return false; + + mMimeType = QCString( 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; + + QPair<const char*,int> maybeSubType; + if ( !parseToken( scursor, send, maybeSubType, false /* no 8bit */ ) ) + return false; + + mMimeSubType = QCString( 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; +} + +//-----</GContentType>------------------------- + + + +//-----<GTokenWithParameterList>------------------------- + +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; + + QPair<const char*,int> maybeToken; + if ( !parseToken( scursor, send, maybeToken, false /* no 8Bit */ ) ) + return false; + + mToken = QCString( 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; +} + +//-----</GTokenWithParameterList>------------------------- + + + +//-----<GIdent>------------------------- + +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; +} + +//-----</GIdent>------------------------- + + + +//-----<GSingleIdent>------------------------- + +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; +} + +//-----</GSingleIdent>------------------------- + + + + +} // namespace Generics + + +//-----<ReturnPath>------------------------- + +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 = QString::null; + 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; +} + +//-----</ReturnPath>------------------------- + + + + +//-----<Generic>------------------------------- + +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; +} + +//-----<Generic>------------------------------- + + +#if !defined(KMIME_NEW_STYLE_CLASSTREE) +//-----<MessageID>----------------------------- + +void MessageID::from7BitString(const QCString &s) +{ + m_id=s; +} + + +QCString MessageID::as7BitString(bool incType) +{ + if(incType) + return ( typeIntro()+m_id ); + else + return m_id; +} + + +void MessageID::fromUnicodeString(const QString &s, const QCString&) +{ + m_id=s.latin1(); //Message-Ids can only contain us-ascii chars +} + + +QString MessageID::asUnicodeString() +{ + return QString::fromLatin1(m_id); +} + + +void MessageID::generate(const QCString &fqdn) +{ + m_id="<"+uniqueString()+"@"+fqdn+">"; +} + +//-----</MessageID>---------------------------- +#endif + + +//-----<Control>------------------------------- + +void Control::from7BitString(const QCString &s) +{ + c_trlMsg=s; +} + + +QCString Control::as7BitString(bool incType) +{ + if(incType) + return ( typeIntro()+c_trlMsg ); + else + return c_trlMsg; +} + + +void Control::fromUnicodeString(const QString &s, const QCString&) +{ + c_trlMsg=s.latin1(); +} + + +QString Control::asUnicodeString() +{ + return QString::fromLatin1(c_trlMsg); +} + +//-----</Control>------------------------------ + + + +#if !defined(KMIME_NEW_STYLE_CLASSTREE) +//-----<AddressField>-------------------------- +void AddressField::from7BitString(const QCString &s) +{ + int pos1=0, pos2=0, type=0; + QCString n; + + //so what do we have here ? + if(s.find( QRegExp("*@*(*)", false, true) )!=-1) type=2; // From: foo@bar.com (John Doe) + else if(s.find( QRegExp("*<*@*>", false, true) )!=-1) type=1; // From: John Doe <foo@bar.com> + else if(s.find( QRegExp("*@*", 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()); + } +} + + +QCString AddressField::as7BitString(bool incType) +{ + QCString ret; + + if(incType && type()[0]!='\0') + ret=typeIntro(); + + if(n_ame.isEmpty()) + ret+=e_mail; + else { + if (isUsAscii(n_ame)) { + QCString 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 QString &s, const QCString &cs) +{ + int pos1=0, pos2=0, type=0; + QCString n; + + e_ncCS=cachedCharset(cs); + + //so what do we have here ? + if(s.find( QRegExp("*@*(*)", false, true) )!=-1) type=2; // From: foo@bar.com (John Doe) + else if(s.find( QRegExp("*<*@*>", false, true) )!=-1) type=1; // From: John Doe <foo@bar.com> + else if(s.find( QRegExp("*@*", 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); +} + + +QString AddressField::asUnicodeString() +{ + if(n_ame.isEmpty()) + return QString(e_mail); + else { + QString s = n_ame; + if (!e_mail.isEmpty()) + s += " <"+e_mail+">"; + return s; + } +} + + +QCString AddressField::nameAs7Bit() +{ + return encodeRFC2047String(n_ame, e_ncCS); +} + + +void AddressField::setNameFrom7Bit(const QCString &s) +{ + n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS()); +} + +//-----</AddressField>------------------------- +#endif + + +//-----<MailCopiesTo>-------------------------- + +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")); +} + +//-----</MailCopiesTo>------------------------- + + + + +//-----<Date>---------------------------------- + +void Date::from7BitString(const QCString &s) +{ + t_ime=KRFCDate::parseDate(s); +} + + +QCString Date::as7BitString(bool incType) +{ + if(incType) + return ( typeIntro()+KRFCDate::rfc2822DateString(t_ime) ); + else + return QCString(KRFCDate::rfc2822DateString(t_ime)); +} + + +void Date::fromUnicodeString(const QString &s, const QCString&) +{ + from7BitString( QCString(s.latin1()) ); +} + + +QString Date::asUnicodeString() +{ + return QString::fromLatin1(as7BitString(false)); +} + + +QDateTime Date::qdt() +{ + QDateTime dt; + dt.setTime_t(t_ime); + return dt; +} + + +int Date::ageInDays() +{ + QDate today=QDate::currentDate(); + return ( qdt().date().daysTo(today) ); +} + +//-----</Date>--------------------------------- + + + +#if !defined(KMIME_NEW_STYLE_CLASSTREE) +//-----<To>------------------------------------ + +void To::from7BitString(const QCString &s) +{ + if(a_ddrList) + a_ddrList->clear(); + else { + a_ddrList=new QPtrList<AddressField>; + a_ddrList->setAutoDelete(true); + } + + KQCStringSplitter 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()); +} + + +QCString To::as7BitString(bool incType) +{ + QCString 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 QString &s, const QCString &cs) +{ + if(a_ddrList) + a_ddrList->clear(); + else { + a_ddrList=new QPtrList<AddressField>; + a_ddrList->setAutoDelete(true); + } + + QStringList l=QStringList::split(",", s); + + QStringList::Iterator it=l.begin(); + for(; it!=l.end(); ++it) + a_ddrList->append(new AddressField( p_arent, (*it), cs )); + + e_ncCS=cachedCharset(cs); +} + + +QString To::asUnicodeString() +{ + if(!a_ddrList) + return QString::null; + + QString 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 QPtrList<AddressField>; + a_ddrList->setAutoDelete(true); + } + + AddressField *add=new AddressField(a); + add->setParent(p_arent); + a_ddrList->append(add); +} + + +void To::emails(QStrList *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(QStringList *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(QStringList *l) +{ + l->clear(); + + for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() ) + l->append( it->asUnicodeString() ); +} + +//-----</To>----------------------------------- +#endif + + +//-----<Newsgroups>---------------------------- + +void Newsgroups::from7BitString(const QCString &s) +{ + g_roups=s; + e_ncCS=cachedCharset("UTF-8"); +} + + +QCString Newsgroups::as7BitString(bool incType) +{ + if(incType) + return (typeIntro()+g_roups); + else + return g_roups; +} + + +void Newsgroups::fromUnicodeString(const QString &s, const QCString&) +{ + g_roups=s.utf8(); + e_ncCS=cachedCharset("UTF-8"); +} + + +QString Newsgroups::asUnicodeString() +{ + return QString::fromUtf8(g_roups); +} + + +QCString 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 QCString(); +} + + +QStringList Newsgroups::getGroups() +{ + QStringList temp = QStringList::split(',', g_roups); + QStringList ret; + QString s; + + for (QStringList::Iterator it = temp.begin(); it != temp.end(); ++it ) { + s = (*it).simplifyWhiteSpace(); + ret.append(s); + } + + return ret; +} + +//-----</Newsgroups>--------------------------- + + + +//-----<Lines>--------------------------------- + +void Lines::from7BitString(const QCString &s) +{ + l_ines=s.toInt(); + e_ncCS=cachedCharset(Latin1); +} + + +QCString Lines::as7BitString(bool incType) +{ + QCString num; + num.setNum(l_ines); + + if(incType) + return ( typeIntro()+num ); + else + return num; +} + + +void Lines::fromUnicodeString(const QString &s, const QCString&) +{ + l_ines=s.toInt(); + e_ncCS=cachedCharset(Latin1); +} + + +QString Lines::asUnicodeString() +{ + QString num; + num.setNum(l_ines); + + return num; +} + +//-----</Lines>-------------------------------- + + + +#if !defined(KMIME_NEW_STYLE_CLASSTREE) +//-----<References>---------------------------- + +void References::from7BitString(const QCString &s) +{ + r_ef=s; + e_ncCS=cachedCharset(Latin1); +} + + +QCString References::as7BitString(bool incType) +{ + if(incType) + return ( typeIntro()+r_ef ); + else + return r_ef; +} + + +void References::fromUnicodeString(const QString &s, const QCString&) +{ + r_ef=s.latin1(); + e_ncCS=cachedCharset(Latin1); +} + + +QString References::asUnicodeString() +{ + return QString::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<r_efLen; i++) { + if(dataPtr[i]=='<') cnt1++; + else if(dataPtr[i]=='>') cnt2++; + } + + if(cnt1<cnt2) return cnt1; + else return cnt2; +} + + +QCString References::first() +{ + p_os=-1; + return next(); +} + + +QCString References::next() +{ + int pos1=0, pos2=0; + QCString ret; + + if(p_os!=0) { + pos2=r_ef.findRev('>', 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; +} + + +QCString References::at(unsigned int i) +{ + QCString 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 QCString &s) +{ + QString temp=r_ef.data(); + temp += " "; + temp += s.data(); + QStringList lst=QStringList::split(' ',temp); + QRegExp exp("^<.+@.+>$"); + + // remove bogus references + QStringList::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,(QString(" %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,(QString(" %1").arg(temp)).latin1()); + lst.remove(temp); + } else + return; + } +} + +//-----</References>--------------------------- +#endif + + +//-----<UserAgent>----------------------------- + +void UserAgent::from7BitString(const QCString &s) +{ + u_agent=s; + e_ncCS=cachedCharset(Latin1); +} + + +QCString UserAgent::as7BitString(bool incType) +{ + if(incType) + return ( typeIntro()+u_agent ); + else + return u_agent; +} + + +void UserAgent::fromUnicodeString(const QString &s, const QCString&) +{ + u_agent=s.latin1(); + e_ncCS=cachedCharset(Latin1); +} + + +QString UserAgent::asUnicodeString() +{ + return QString::fromLatin1(u_agent); +} + +//-----</UserAgent>---------------------------- + + + +#if !defined(KMIME_NEW_STYLE_CLASSTREE) +//-----<Content-Type>-------------------------- + +void ContentType::from7BitString(const QCString &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); +} + + +QCString ContentType::as7BitString(bool incType) +{ + if(incType) + return (typeIntro()+m_imeType+p_arams); + else + return (m_imeType+p_arams); +} + + +void ContentType::fromUnicodeString(const QString &s, const QCString&) +{ + from7BitString( QCString(s.latin1()) ); +} + + +QString ContentType::asUnicodeString() +{ + return QString::fromLatin1(as7BitString(false)); +} + + +QCString ContentType::mediaType() +{ + int pos=m_imeType.find('/'); + if(pos==-1) + return m_imeType; + else + return m_imeType.left(pos); +} + + +QCString ContentType::subType() +{ + int pos=m_imeType.find('/'); + if(pos==-1) + return QCString(); + else + return m_imeType.mid(pos, m_imeType.length()-pos); +} + + +void ContentType::setMimeType(const QCString &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); +} + + +QCString ContentType::charset() +{ + QCString ret=getParameter("charset"); + if( ret.isEmpty() || forceCS() ) { //we return the default-charset if necessary + ret=defaultCS(); + } + return ret; +} + + +void ContentType::setCharset(const QCString &s) +{ + setParameter("charset", s); +} + + +QCString ContentType::boundary() +{ + return getParameter("boundary"); +} + + +void ContentType::setBoundary(const QCString &s) +{ + setParameter("boundary", s, true); +} + + +QString ContentType::name() +{ + const char *dummy=0; + return ( decodeRFC2047String(getParameter("name"), &dummy, defaultCS(), forceCS()) ); +} + + +void ContentType::setName(const QString &s, const QCString &cs) +{ + e_ncCS=cs; + + if (isUsAscii(s)) { + QCString 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); + } +} + + +QCString ContentType::id() +{ + return (getParameter("id")); +} + + +void ContentType::setId(const QCString &s) +{ + setParameter("id", s, true); +} + + +int ContentType::partialNumber() +{ + QCString p=getParameter("number"); + if(!p.isEmpty()) + return p.toInt(); + else + return -1; +} + + +int ContentType::partialCount() +{ + QCString p=getParameter("total"); + if(!p.isEmpty()) + return p.toInt(); + else + return -1; +} + + +void ContentType::setPartialParams(int total, int number) +{ + QCString num; + num.setNum(number); + setParameter("number", num); + num.setNum(total); + setParameter("total", num); +} + + +QCString ContentType::getParameter(const char *name) +{ + QCString 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 QCString &name, const QCString &value, bool doubleQuotes) +{ + int pos1=0, pos2=0; + QCString param; + + if(doubleQuotes) + param=name+"=\""+value+"\""; + else + param=name+"="+value; + + pos1=p_arams.find(name, 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); + } +} + +//-----</Content-Type>------------------------- + + + +//-----<CTEncoding>---------------------------- + +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 QCString &s) +{ + QCString 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); +} + + +QCString CTEncoding::as7BitString(bool incType) +{ + QCString 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 QString &s, const QCString&) +{ + from7BitString( QCString(s.latin1()) ); +} + + +QString CTEncoding::asUnicodeString() +{ + return QString::fromLatin1(as7BitString(false)); +} + +//-----</CTEncoding>--------------------------- + + + +//-----<CDisposition>-------------------------- + +void CDisposition::from7BitString(const QCString &s) +{ + if(strncasecmp(s.data(), "attachment", 10)==0) + d_isp=CDattachment; + else d_isp=CDinline; + + int pos=s.find("filename=", 0, false); + QCString fn; + if(pos>-1) { + pos+=9; + fn=s.mid(pos, s.length()-pos); + removeQuots(fn); + f_ilename=decodeRFC2047String(fn, &e_ncCS, defaultCS(), forceCS()); + } +} + + +QCString CDisposition::as7BitString(bool incType) +{ + QCString ret; + if(d_isp==CDattachment) + ret="attachment"; + else + ret="inline"; + + if(!f_ilename.isEmpty()) { + if (isUsAscii(f_ilename)) { + QCString 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 QString &s, const QCString &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); +} + + +QString CDisposition::asUnicodeString() +{ + QString ret; + if(d_isp==CDattachment) + ret="attachment"; + else + ret="inline"; + + if(!f_ilename.isEmpty()) + ret+="; filename=\""+f_ilename+"\""; + + return ret; +} + +//-----</CDisposition>------------------------- +#endif +} // namespace Headers + +} // namespace KMime |