41#include "kmime_headers_p.h"
43#include "kmime_util.h"
44#include "kmime_util_p.h"
47#include "kmime_header_parsing.h"
49#include "kmime_warning.h"
51#include <QtCore/QTextCodec>
52#include <QtCore/QString>
53#include <QtCore/QStringList>
62bool registerHeaderHelper()
65 if ( QByteArray( dummy.type() ).isEmpty() ) {
69 return KMime::HeaderFactory::self()->registerHeader<T>();
73#define kmime_register_header( subclass ) \
74namespace { const bool dummyForRegistering##subclass = registerHeaderHelper<subclass>(); }
77#define kmime_mk_trivial_ctor( subclass, baseclass ) \
78subclass::subclass( Content *parent ) : baseclass( parent ) \
83subclass::subclass( Content *parent, const QByteArray &s ) : baseclass( parent ) \
85 from7BitString( s ); \
88subclass::subclass( Content *parent, const QString &s, const QByteArray &charset ) : \
91 fromUnicodeString( s, charset ); \
94subclass::~subclass() {} \
96kmime_register_header( subclass )
100#define kmime_mk_trivial_ctor_with_dptr( subclass, baseclass ) \
101subclass::subclass( Content *parent ) : baseclass( new subclass##Private, parent ) \
106subclass::subclass( Content *parent, const QByteArray &s ) : baseclass( new subclass##Private, parent ) \
108 from7BitString( s ); \
111subclass::subclass( Content *parent, const QString &s, const QByteArray &charset ) : \
112 baseclass( new subclass##Private, parent ) \
114 fromUnicodeString( s, charset ); \
117subclass::~subclass() {} \
119kmime_register_header( subclass )
123#define kmime_mk_trivial_ctor_with_name( subclass, baseclass, name ) \
124kmime_mk_trivial_ctor( subclass, baseclass ) \
126const char *subclass::type() const \
128 return staticType(); \
130const char *subclass::staticType() { return #name; }
132#define kmime_mk_trivial_ctor_with_name_and_dptr( subclass, baseclass, name ) \
133kmime_mk_trivial_ctor_with_dptr( subclass, baseclass ) \
134const char *subclass::type() const { return staticType(); } \
135const char *subclass::staticType() { return #name; }
137#define kmime_mk_dptr_ctor( subclass, baseclass ) \
138subclass::subclass( subclass##Private *d, KMime::Content *parent ) : baseclass( d, parent ) {}
140using namespace KMime;
141using namespace KMime::Headers;
142using namespace KMime::Types;
143using namespace KMime::HeaderParsing;
149 d_ptr( new BasePrivate )
189 d_ptr->encCS = cachedCharset( cs );
209 return qstricmp( t,
type() ) == 0;
214 return qstrnicmp(
type(),
"Content-", 8 ) == 0;
219 return qstrncmp(
type(),
"X-", 2 ) == 0;
224 return QByteArray(
type() ) +
": ";
234kmime_mk_dptr_ctor( Unstructured,
Base )
237Unstructured::Unstructured(
Content *p ) :
Base( new UnstructuredPrivate, p )
241Unstructured::Unstructured(
Content *p,
const QByteArray &s ) :
Base( new UnstructuredPrivate, p )
246Unstructured::Unstructured(
Content *p,
const QString &s,
const QByteArray &cs ) :
Base( new UnstructuredPrivate, p )
251Unstructured::~Unstructured()
255void Unstructured::from7BitString(
const QByteArray &s )
258 d->decoded = decodeRFC2047String( s, d->encCS, defaultCharset(), forceDefaultCharset() );
261QByteArray Unstructured::as7BitString(
bool withHeaderType )
const
263 const Q_D( Unstructured );
265 if ( withHeaderType ) {
266 result = typeIntro();
268 result += encodeRFC2047String( d->decoded, d->encCS ) ;
273void Unstructured::fromUnicodeString(
const QString &s,
const QByteArray &b )
277 d->encCS = cachedCharset( b );
280QString Unstructured::asUnicodeString()
const
282 return d_func()->decoded;
285void Unstructured::clear()
288 d->decoded.truncate( 0 );
291bool Unstructured::isEmpty()
const
293 return d_func()->decoded.isEmpty();
300Structured::Structured(
Content *p ) :
Base( new StructuredPrivate, p )
304Structured::Structured(
Content *p,
const QByteArray &s ) :
Base( new StructuredPrivate, p )
309Structured::Structured(
Content *p,
const QString &s,
const QByteArray &cs ) :
Base( new StructuredPrivate, p )
314kmime_mk_dptr_ctor( Structured,
Base )
316Structured::~Structured()
320void Structured::from7BitString(
const QByteArray &s )
323 if ( d->encCS.isEmpty() ) {
324 d->encCS = defaultCharset();
326 const char *cursor = s.constData();
327 parse( cursor, cursor + s.length() );
330QString Structured::asUnicodeString()
const
332 return QString::fromLatin1( as7BitString(
false ) );
335void Structured::fromUnicodeString(
const QString &s,
const QByteArray &b )
338 d->encCS = cachedCharset( b );
339 from7BitString( s.toLatin1() );
346Address::Address(
Content *p ) : Structured( new AddressPrivate, p )
350Address::Address(
Content *p,
const QByteArray &s ) : Structured( new AddressPrivate, p )
355Address::Address(
Content *p,
const QString &s,
const QByteArray &cs ) : Structured( new AddressPrivate, p )
360kmime_mk_dptr_ctor( Address, Structured )
367static bool stringToMailbox(
const QByteArray &address,
370 Types::AddrSpec addrSpec;
372 const char *cursor = address.constData();
373 if ( !parseAngleAddr( cursor, cursor + address.length(), addrSpec ) ) {
374 if ( !parseAddrSpec( cursor, cursor + address.length(), addrSpec ) ) {
375 kWarning() <<
"Invalid address";
387kmime_mk_trivial_ctor_with_dptr( MailboxList, Address )
388kmime_mk_dptr_ctor( MailboxList, Address )
390QByteArray MailboxList::as7BitString(
bool withHeaderType )
const
392 const Q_D( MailboxList );
398 if ( withHeaderType ) {
405 rv.resize( rv.length() - 2 );
409void MailboxList::fromUnicodeString(
const QString &s,
const QByteArray &b )
412 d->encCS = cachedCharset( b );
413 from7BitString( encodeRFC2047Sentence( s, b ) );
416QString MailboxList::asUnicodeString()
const
418 return prettyAddresses().join( QLatin1String(
", " ) );
421void MailboxList::clear()
424 d->mailboxList.clear();
427bool MailboxList::isEmpty()
const
429 return d_func()->mailboxList.isEmpty();
435 d->mailboxList.append( mbox );
438void MailboxList::addAddress(
const QByteArray &address,
439 const QString &displayName )
443 if ( stringToMailbox( address, displayName, mbox ) ) {
444 d->mailboxList.append( mbox );
448QList< QByteArray > MailboxList::addresses()
const
450 QList<QByteArray> rv;
457QStringList MailboxList::displayNames()
const
461 rv.append( mbox.
name() );
466QStringList MailboxList::prettyAddresses()
const
475Types::Mailbox::List MailboxList::mailboxes()
const
477 return d_func()->mailboxList;
480bool MailboxList::parse(
const char* &scursor,
const char *
const send,
489 QList<Types::Address> maybeAddressList;
490 if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) {
494 d->mailboxList.clear();
497 QList<Types::Address>::Iterator it;
498 for ( it = maybeAddressList.begin(); it != maybeAddressList.end() ; ++it ) {
499 if ( !( *it ).displayName.isEmpty() ) {
500 KMIME_WARN <<
"mailbox groups in header disallowing them! Name: \""
501 << ( *it ).displayName <<
"\"" << endl;
503 d->mailboxList += ( *it ).mailboxList;
513kmime_mk_trivial_ctor_with_dptr( SingleMailbox, MailboxList )
516bool SingleMailbox::parse(
const char* &scursor,
const char *
const send,
520 if ( !MailboxList::parse( scursor, send, isCRLF ) ) {
524 if ( d->mailboxList.count() > 1 ) {
525 KMIME_WARN <<
"multiple mailboxes in header allowing only a single one!"
536kmime_mk_trivial_ctor_with_dptr( AddressList, Address )
537kmime_mk_dptr_ctor( AddressList, Address )
540QByteArray AddressList::as7BitString(
bool withHeaderType )
const
542 const Q_D( AddressList );
543 if ( d->addressList.isEmpty() ) {
548 if ( withHeaderType ) {
551 foreach (
const Types::Address &addr, d->addressList ) {
557 rv.resize( rv.length() - 2 );
561void AddressList::fromUnicodeString(
const QString &s,
const QByteArray &b )
564 d->encCS = cachedCharset( b );
565 from7BitString( encodeRFC2047Sentence( s, b ) );
568QString AddressList::asUnicodeString()
const
570 return prettyAddresses().join( QLatin1String(
", " ) );
573void AddressList::clear()
576 d->addressList.clear();
579bool AddressList::isEmpty()
const
581 return d_func()->addressList.isEmpty();
588 addr.mailboxList.append( mbox );
589 d->addressList.append( addr );
592void AddressList::addAddress(
const QByteArray &address,
593 const QString &displayName )
598 if ( stringToMailbox( address, displayName, mbox ) ) {
599 addr.mailboxList.append( mbox );
600 d->addressList.append( addr );
604QList< QByteArray > AddressList::addresses()
const
606 QList<QByteArray> rv;
607 foreach (
const Types::Address &addr, d_func()->addressList ) {
615QStringList AddressList::displayNames()
const
618 foreach (
const Types::Address &addr, d_func()->addressList ) {
620 rv.append( mbox.
name() );
626QStringList AddressList::prettyAddresses()
const
629 foreach (
const Types::Address &addr, d_func()->addressList ) {
637Types::Mailbox::List AddressList::mailboxes()
const
639 Types::Mailbox::List rv;
640 foreach (
const Types::Address &addr, d_func()->addressList ) {
648bool AddressList::parse(
const char* &scursor,
const char *
const send,
652 QList<Types::Address> maybeAddressList;
653 if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) {
657 d->addressList = maybeAddressList;
666kmime_mk_trivial_ctor_with_dptr( Token, Structured )
667kmime_mk_dptr_ctor( Token, Structured )
670QByteArray Token::as7BitString(
bool withHeaderType )
const
675 if ( withHeaderType ) {
676 return typeIntro() + d_func()->token;
678 return d_func()->token;
687bool Token::isEmpty()
const
689 return d_func()->token.isEmpty();
692QByteArray Token::token()
const
694 return d_func()->token;
697void Token::setToken(
const QByteArray &t )
703bool Token::parse(
const char* &scursor,
const char *
const send,
bool isCRLF )
707 eatCFWS( scursor, send, isCRLF );
709 if ( scursor == send ) {
713 QPair<const char*, int> maybeToken;
714 if ( !parseToken( scursor, send, maybeToken,
false ) ) {
717 d->token = QByteArray( maybeToken.first, maybeToken.second );
720 eatCFWS( scursor, send, isCRLF );
721 if ( scursor != send ) {
722 KMIME_WARN <<
"trailing garbage after token in header allowing "
723 "only a single token!" << endl;
733kmime_mk_trivial_ctor_with_dptr( PhraseList, Structured )
736QByteArray PhraseList::as7BitString(
bool withHeaderType )
const
738 const Q_D( PhraseList );
744 if ( withHeaderType ) {
748 for (
int i = 0; i < d->phraseList.count(); ++i ) {
750 rv += encodeRFC2047String( d->phraseList[i], d->encCS,
false,
false );
751 if ( i != d->phraseList.count() - 1 ) {
759QString PhraseList::asUnicodeString()
const
761 return d_func()->phraseList.join( QLatin1String(
", " ) );
764void PhraseList::clear()
767 d->phraseList.clear();
770bool PhraseList::isEmpty()
const
772 return d_func()->phraseList.isEmpty();
775QStringList PhraseList::phrases()
const
777 return d_func()->phraseList;
780bool PhraseList::parse(
const char* &scursor,
const char *
const send,
784 d->phraseList.clear();
786 while ( scursor != send ) {
787 eatCFWS( scursor, send, isCRLF );
789 if ( scursor == send ) {
793 if ( *scursor ==
',' ) {
799 if ( !parsePhrase( scursor, send, maybePhrase, isCRLF ) ) {
802 d->phraseList.append( maybePhrase );
804 eatCFWS( scursor, send, isCRLF );
806 if ( scursor == send ) {
810 if ( *scursor ==
',' ) {
822kmime_mk_trivial_ctor_with_dptr( DotAtom, Structured )
825QByteArray DotAtom::as7BitString(
bool withHeaderType )
const
832 if ( withHeaderType ) {
836 rv += d_func()->dotAtom.toLatin1();
840QString DotAtom::asUnicodeString()
const
842 return d_func()->dotAtom;
851bool DotAtom::isEmpty()
const
853 return d_func()->dotAtom.isEmpty();
856bool DotAtom::parse(
const char* &scursor,
const char *
const send,
860 QString maybeDotAtom;
861 if ( !parseDotAtom( scursor, send, maybeDotAtom, isCRLF ) ) {
865 d->dotAtom = maybeDotAtom;
867 eatCFWS( scursor, send, isCRLF );
868 if ( scursor != send ) {
869 KMIME_WARN <<
"trailing garbage after dot-atom in header allowing "
870 "only a single dot-atom!" << endl;
880kmime_mk_trivial_ctor_with_dptr( Parametrized, Structured )
881kmime_mk_dptr_ctor( Parametrized, Structured )
884QByteArray Parametrized::as7BitString(
bool withHeaderType )
const
886 const Q_D( Parametrized );
892 if ( withHeaderType ) {
897 for ( QMap<QString, QString>::ConstIterator it = d->parameterHash.constBegin();
898 it != d->parameterHash.constEnd(); ++it ) {
904 if ( isUsAscii( it.value() ) ) {
905 rv += it.key().toLatin1() +
'=';
906 QByteArray tmp = it.value().toLatin1();
907 addQuotes( tmp,
true );
910 if ( useOutlookAttachmentEncoding() ) {
911 rv += it.key().toLatin1() +
'=';
912 kDebug() <<
"doing:" << it.value() << QLatin1String( d->encCS );
913 rv +=
"\"" + encodeRFC2047String( it.value(), d->encCS ) +
"\"";
915 rv += it.key().toLatin1() +
"*=";
916 rv += encodeRFC2231String( it.value(), d->encCS );
924QString Parametrized::parameter(
const QString &key )
const
926 return d_func()->parameterHash.value( key.toLower() );
929bool Parametrized::hasParameter(
const QString &key )
const
931 return d_func()->parameterHash.contains( key.toLower() );
934void Parametrized::setParameter(
const QString &key,
const QString &value )
937 d->parameterHash.insert( key.toLower(), value );
940bool Parametrized::isEmpty()
const
942 return d_func()->parameterHash.isEmpty();
945void Parametrized::clear()
948 d->parameterHash.clear();
951bool Parametrized::parse(
const char *& scursor,
const char *
const send,
955 d->parameterHash.clear();
957 if ( !parseParameterListWithCharset( scursor, send, d->parameterHash, charset, isCRLF ) ) {
969kmime_mk_trivial_ctor_with_dptr( Ident, Address )
970kmime_mk_dptr_ctor( Ident, Address )
973QByteArray Ident::as7BitString(
bool withHeaderType )
const
976 if ( d->msgIdList.isEmpty() ) {
981 if ( withHeaderType ) {
984 foreach (
const Types::AddrSpec &addr, d->msgIdList ) {
985 if ( !addr.isEmpty() ) {
986 const QString asString = addr.asString();
988 if ( !asString.isEmpty() ) {
989 rv += asString.toLatin1();
994 if ( !rv.isEmpty() ) {
995 rv.resize( rv.length() - 1 );
1003 d->msgIdList.clear();
1004 d->cachedIdentifier.clear();
1007bool Ident::isEmpty()
const
1009 return d_func()->msgIdList.isEmpty();
1012bool Ident::parse(
const char* &scursor,
const char *
const send,
bool isCRLF )
1022 d->msgIdList.clear();
1023 d->cachedIdentifier.clear();
1025 while ( scursor != send ) {
1026 eatCFWS( scursor, send, isCRLF );
1028 if ( scursor == send ) {
1032 if ( *scursor ==
',' ) {
1037 AddrSpec maybeMsgId;
1038 if ( !parseAngleAddr( scursor, send, maybeMsgId, isCRLF ) ) {
1041 d->msgIdList.append( maybeMsgId );
1043 eatCFWS( scursor, send, isCRLF );
1045 if ( scursor == send ) {
1049 if ( *scursor ==
',' ) {
1056QList<QByteArray> Ident::identifiers()
const
1058 QList<QByteArray> rv;
1059 foreach (
const Types::AddrSpec &addr, d_func()->msgIdList ) {
1060 if ( !addr.isEmpty() ) {
1061 const QString asString = addr.asString();
1062 if ( !asString.isEmpty() ) {
1063 rv.append( asString.toLatin1() );
1070void Ident::appendIdentifier(
const QByteArray &
id )
1073 QByteArray tmp = id;
1074 if ( !tmp.startsWith(
'<' ) ) {
1077 if ( !tmp.endsWith(
'>' ) ) {
1081 const char *cursor = tmp.constData();
1082 if ( parseAngleAddr( cursor, cursor + tmp.length(), msgId ) ) {
1083 d->msgIdList.append( msgId );
1085 kWarning() <<
"Unable to parse address spec!";
1094kmime_mk_trivial_ctor_with_dptr( SingleIdent, Ident )
1095kmime_mk_dptr_ctor( SingleIdent, Ident )
1098QByteArray SingleIdent::identifier()
const
1100 if ( d_func()->msgIdList.isEmpty() ) {
1101 return QByteArray();
1104 if ( d_func()->cachedIdentifier.isEmpty() ) {
1105 const Types::AddrSpec &addr = d_func()->msgIdList.first();
1106 if ( !addr.isEmpty() ) {
1107 const QString asString = addr.asString();
1108 if ( !asString.isEmpty() ) {
1109 d_func()->cachedIdentifier = asString.toLatin1();
1114 return d_func()->cachedIdentifier;
1117void SingleIdent::setIdentifier(
const QByteArray &
id )
1120 d->msgIdList.clear();
1121 d->cachedIdentifier.clear();
1122 appendIdentifier(
id );
1125bool SingleIdent::parse(
const char* &scursor,
const char *
const send,
1129 if ( !Ident::parse( scursor, send, isCRLF ) ) {
1133 if ( d->msgIdList.count() > 1 ) {
1134 KMIME_WARN <<
"more than one msg-id in header "
1135 <<
"allowing only a single one!" << endl;
1147kmime_mk_trivial_ctor_with_name_and_dptr(
ReturnPath, Generics::Address, Return-Path )
1153 return QByteArray();
1157 if ( withHeaderType ) {
1160 rv +=
'<' + d_func()->mailbox.as7BitString( d_func()->encCS ) +
'>';
1167 d->mailbox.setAddress( Types::AddrSpec() );
1168 d->mailbox.setName( QString() );
1174 return !d->mailbox.hasAddress() && !d->mailbox.hasName();
1177bool ReturnPath::parse(
const char* &scursor,
const char *
const send,
1181 eatCFWS( scursor, send, isCRLF );
1182 if ( scursor == send ) {
1186 const char * oldscursor = scursor;
1189 if ( !parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) {
1191 scursor = oldscursor;
1192 if ( *scursor !=
'<' ) {
1196 eatCFWS( scursor, send, isCRLF );
1197 if ( scursor == send || *scursor !=
'>' ) {
1203 AddrSpec emptyAddrSpec;
1204 maybeMailbox.
setName( QString() );
1208 if ( maybeMailbox.
hasName() ) {
1209 KMIME_WARN <<
"display-name \"" << maybeMailbox.
name()
1210 <<
"\" in Return-Path!" << endl;
1213 d->mailbox = maybeMailbox;
1216 eatCFWS( scursor, send, isCRLF );
1218 if ( scursor != send ) {
1219 KMIME_WARN <<
"trailing garbage after angle-addr in Return-Path!" << endl;
1230Generic::Generic() : Generics::Unstructured( new GenericPrivate )
1234Generic::Generic(
const char *t ) : Generics::Unstructured( new GenericPrivate )
1239Generic::Generic(
const char *t,
Content *p )
1240 : Generics::Unstructured( new GenericPrivate, p )
1245Generic::Generic(
const char *t,
Content *p,
const QByteArray &s )
1246 : Generics::Unstructured( new GenericPrivate, p )
1248 from7BitString( s );
1252Generic::Generic(
const char *t,
Content *p,
const QString &s,
const QByteArray &cs )
1253 : Generics::Unstructured( new GenericPrivate, p )
1255 fromUnicodeString( s, cs );
1268 Unstructured::clear();
1273 return d_func()->type == 0 || Unstructured::isEmpty();
1278 return d_func()->type;
1281void Generic::setType(
const char *type )
1288 d->type =
new char[strlen(
type )+1];
1289 strcpy( d->type,
type );
1300kmime_mk_trivial_ctor_with_name(
MessageID, Generics::SingleIdent,
Message-ID )
1305 setIdentifier(
'<' + uniqueString() +
'@' + fqdn +
'>' );
1313kmime_mk_trivial_ctor_with_name_and_dptr(
Control, Generics::Structured,
Control )
1316QByteArray
Control::as7BitString(
bool withHeaderType )
const
1320 return QByteArray();
1324 if ( withHeaderType ) {
1329 if ( !d->parameter.isEmpty() ) {
1330 rv +=
' ' + d->parameter;
1339 d->parameter.clear();
1344 return d_func()->name.isEmpty();
1349 return d_func()->name;
1354 return d_func()->parameter;
1359 return d_func()->name.toLower() ==
"cancel";
1366 d->parameter = msgid;
1369bool Control::parse(
const char* &scursor,
const char *
const send,
bool isCRLF )
1373 eatCFWS( scursor, send, isCRLF );
1374 if ( scursor == send ) {
1377 const char *start = scursor;
1378 while ( scursor != send && !isspace( *scursor ) ) {
1381 d->name = QByteArray( start, scursor - start );
1382 eatCFWS( scursor, send, isCRLF );
1383 d->parameter = QByteArray( scursor, send - scursor );
1393 Generics::AddressList, Mail-Copies-
To )
1399 if ( withHeaderType ) {
1402 if ( !AddressList::isEmpty() ) {
1403 rv += AddressList::as7BitString(
false );
1405 if ( d_func()->alwaysCopy ) {
1407 }
else if ( d_func()->neverCopy ) {
1416 if ( !AddressList::isEmpty() ) {
1417 return AddressList::asUnicodeString();
1420 return QLatin1String(
"poster" );
1423 return QLatin1String(
"nobody" );
1431 AddressList::clear();
1432 d->alwaysCopy =
false;
1433 d->neverCopy =
false;
1438 return AddressList::isEmpty() && !( d_func()->alwaysCopy || d_func()->neverCopy );
1443 return !AddressList::isEmpty() || d_func()->alwaysCopy;
1450 d->alwaysCopy =
true;
1455 return d_func()->neverCopy;
1462 d->neverCopy =
true;
1465bool MailCopiesTo::parse(
const char *& scursor,
const char *
const send,
1470 if ( send - scursor == 5 ) {
1471 if ( qstrnicmp(
"never", scursor, 5 ) == 0 ) {
1472 d->neverCopy =
true;
1476 if ( send - scursor == 6 ) {
1477 if ( qstrnicmp(
"always", scursor, 6 ) == 0 || qstrnicmp(
"poster", scursor, 6 ) == 0 ) {
1478 d->alwaysCopy =
true;
1481 if ( qstrnicmp(
"nobody", scursor, 6 ) == 0 ) {
1482 d->neverCopy =
true;
1486 return AddressList::parse( scursor, send, isCRLF );
1494kmime_mk_trivial_ctor_with_name_and_dptr(
Date, Generics::Structured,
Date )
1497QByteArray
Date::as7BitString(
bool withHeaderType )
const
1500 return QByteArray();
1504 if ( withHeaderType ) {
1507 rv += d_func()->dateTime.toString( KDateTime::RFCDateDay ).toLatin1();
1514 d->dateTime = KDateTime();
1519 return d_func()->dateTime.isNull() || !d_func()->dateTime.isValid();
1524 return d_func()->dateTime;
1535 QDate today = QDate::currentDate();
1536 return dateTime().date().daysTo( today );
1539bool Date::parse(
const char* &scursor,
const char *
const send,
bool isCRLF )
1542 return parseDateTime( scursor, send, d->dateTime, isCRLF );
1558 return QByteArray();
1562 if ( withHeaderType ) {
1566 for (
int i = 0; i < d->groups.count(); ++i ) {
1567 rv += d->groups[ i ];
1568 if ( i != d->groups.count() - 1 ) {
1579 from7BitString( s.toUtf8() );
1580 d->encCS = cachedCharset(
"UTF-8" );
1596 return d_func()->groups.isEmpty();
1601 return d_func()->groups;
1612 return d_func()->groups.count() >= 2;
1615bool Newsgroups::parse(
const char* &scursor,
const char *
const send,
bool isCRLF )
1620 eatCFWS( scursor, send, isCRLF );
1621 if ( scursor != send && *scursor ==
',' ) {
1624 eatCFWS( scursor, send, isCRLF );
1625 if ( scursor == send ) {
1628 const char *start = scursor;
1629 while ( scursor != send && !isspace( *scursor ) && *scursor !=
',' ) {
1632 QByteArray group( start, scursor - start );
1633 d->groups.append( group );
1643kmime_mk_trivial_ctor_with_name_and_dptr(
Lines, Generics::Structured,
Lines )
1646QByteArray
Lines::as7BitString(
bool withHeaderType )
const
1649 return QByteArray();
1653 num.setNum( d_func()->lines );
1655 if ( withHeaderType ) {
1656 return typeIntro() + num;
1666 return QString::number( d_func()->lines );
1677 return d_func()->lines == -1;
1682 return d_func()->lines;
1691bool Lines::parse(
const char* &scursor,
const char*
const send,
bool isCRLF )
1694 eatCFWS( scursor, send, isCRLF );
1695 if ( parseDigits( scursor, send, d->lines ) == 0 ) {
1707kmime_mk_trivial_ctor_with_name_and_dptr(
ContentType, Generics::Parametrized,
1713 return d_func()->
mimeType.isEmpty();
1719 d->category = CCsingle;
1720 d->mimeType.clear();
1721 Parametrized::clear();
1727 return QByteArray();
1731 if ( withHeaderType ) {
1736 if ( !Parametrized::isEmpty() ) {
1737 rv +=
"; " + Parametrized::as7BitString(
false );
1752 const int pos = d->mimeType.indexOf(
'/' );
1756 return d->mimeType.left( pos );
1763 const int pos = d->mimeType.indexOf(
'/' );
1765 return QByteArray();
1767 return d->mimeType.mid( pos + 1 );
1775 Parametrized::clear();
1778 d->category = CCcontainer;
1780 d->category = CCsingle;
1787 const int len = strlen( mediatype );
1788 return qstrnicmp( d->mimeType.constData(), mediatype, len ) == 0 &&
1789 ( d->mimeType.at( len ) ==
'/' || d->mimeType.size() == len );
1795 const int pos = d->mimeType.indexOf(
'/' );
1799 const int len = strlen( subtype );
1800 return qstrnicmp( d->mimeType.constData() + pos + 1, subtype, len ) == 0 &&
1801 d->mimeType.size() == pos + len + 1;
1811 return ( qstricmp( d_func()->
mimeType.constData(),
"text/plain" ) == 0 ||
isEmpty() );
1816 return qstricmp( d_func()->
mimeType.constData(),
"text/html" ) == 0;
1831 return qstricmp( d_func()->
mimeType.constData(),
"message/partial" ) == 0;
1836 QByteArray ret = parameter( QLatin1String(
"charset" ) ).toLatin1();
1846 setParameter( QLatin1String(
"charset" ), QString::fromLatin1( s ) );
1851 return parameter( QLatin1String(
"boundary" ) ).toLatin1();
1856 setParameter( QLatin1String(
"boundary" ), QString::fromLatin1( s ) );
1861 return parameter( QLatin1String(
"name" ) );
1868 setParameter( QLatin1String(
"name" ), s );
1873 return parameter( QLatin1String(
"id" ) ).toLatin1();
1878 setParameter( QLatin1String(
"id" ), QString::fromLatin1( s ) );
1883 QByteArray p = parameter( QLatin1String(
"number" ) ).toLatin1();
1884 if ( !p.isEmpty() ) {
1893 QByteArray p = parameter( QLatin1String(
"total" ) ).toLatin1();
1894 if ( !p.isEmpty() ) {
1901contentCategory ContentType::category()
const
1903 return d_func()->category;
1906void ContentType::setCategory( contentCategory c )
1914 setParameter( QLatin1String(
"number" ), QString::number( number ) );
1915 setParameter( QLatin1String(
"total" ), QString::number( total ) );
1918bool ContentType::parse(
const char* &scursor,
const char *
const send,
1925 eatCFWS( scursor, send, isCRLF );
1926 if ( scursor == send ) {
1931 QPair<const char*, int> maybeMimeType;
1932 if ( !parseToken( scursor, send, maybeMimeType,
false ) ) {
1937 eatCFWS( scursor, send, isCRLF );
1938 if ( scursor == send || *scursor !=
'/' ) {
1942 eatCFWS( scursor, send, isCRLF );
1943 if ( scursor == send ) {
1947 QPair<const char*, int> maybeSubType;
1948 if ( !parseToken( scursor, send, maybeSubType,
false ) ) {
1952 d->mimeType.reserve( maybeMimeType.second + maybeSubType.second + 1 );
1953 d->mimeType = QByteArray( maybeMimeType.first, maybeMimeType.second ).toLower()
1954 +
'/' + QByteArray( maybeSubType.first, maybeSubType.second ).toLower();
1957 eatCFWS( scursor, send, isCRLF );
1958 if ( scursor == send ) {
1962 if ( *scursor !=
';' ) {
1967 if ( !Parametrized::parse( scursor, send, isCRLF ) ) {
1974 d->category = CCcontainer;
1976 d->category = CCsingle;
1985kmime_mk_trivial_ctor_with_name_and_dptr(
ContentID, SingleIdent,
Content-ID )
1986kmime_mk_dptr_ctor(
ContentID, SingleIdent )
1988bool ContentID::parse(
const char* &scursor,
const char *
const send,
bool isCRLF )
1994 const char* origscursor = scursor;
1995 if ( !SingleIdent::parse ( scursor, send, isCRLF ) ) {
1996 scursor = origscursor;
1997 d->msgIdList.clear();
1998 d->cachedIdentifier.clear();
2000 while ( scursor != send ) {
2001 eatCFWS ( scursor, send, isCRLF );
2003 if ( scursor == send ) {
2007 if ( *scursor ==
',' ) {
2012 AddrSpec maybeContentId;
2014 if ( scursor == send || *scursor !=
'<' ) {
2019 eatCFWS ( scursor, send, isCRLF );
2020 if ( scursor == send ) {
2026 if( !parseDotAtom(scursor, send, result,
false) ) {
2030 eatCFWS ( scursor, send, isCRLF );
2031 if ( scursor == send || *scursor !=
'>' ) {
2037 maybeContentId.localPart = result;
2038 d->msgIdList.append ( maybeContentId );
2040 eatCFWS ( scursor, send, isCRLF );
2042 if ( scursor == send ) {
2046 if ( *scursor ==
',' ) {
2064 Generics::Token,
Content-Transfer-Encoding )
2067typedef struct {
const char *s;
int e; } encTableType;
2069static const encTableType encTable[] =
2073 {
"quoted-printable",
CEquPr },
2090 return d_func()->cte;
2098 for (
int i = 0; encTable[i].s != 0; ++i ) {
2099 if ( d->cte == encTable[i].e ) {
2100 setToken( encTable[i].s );
2108 return d_func()->decoded;
2123bool ContentTransferEncoding::parse(
const char *& scursor,
2124 const char *
const send,
bool isCRLF )
2128 if ( !Token::parse( scursor, send, isCRLF ) ) {
2133 for (
int i = 0; encTable[i].s != 0; ++i ) {
2134 if ( qstricmp( token().constData(), encTable[i].s ) == 0 ) {
2149 Generics::Parametrized,
Content-Disposition )
2155 return QByteArray();
2159 if ( withHeaderType ) {
2165 }
else if ( d_func()->disposition ==
CDinline ) {
2168 return QByteArray();
2171 if ( !Parametrized::isEmpty() ) {
2172 rv +=
"; " + Parametrized::as7BitString(
false );
2180 return d_func()->disposition ==
CDInvalid;
2187 Parametrized::clear();
2192 return d_func()->disposition;
2198 d->disposition = disp;
2203 return parameter( QLatin1String(
"filename" ) );
2208 setParameter( QLatin1String(
"filename" ),
filename );
2211bool ContentDisposition::parse(
const char *& scursor,
const char *
const send,
2219 eatCFWS( scursor, send, isCRLF );
2220 if ( scursor == send ) {
2224 QPair<const char*, int> maybeToken;
2225 if ( !parseToken( scursor, send, maybeToken,
false ) ) {
2229 token = QByteArray( maybeToken.first, maybeToken.second ).toLower();
2230 if ( token ==
"inline" ) {
2232 }
else if ( token ==
"attachment" ) {
2239 eatCFWS( scursor, send, isCRLF );
2240 if ( scursor == send ) {
2244 if ( *scursor !=
';' ) {
2249 return Parametrized::parse( scursor, send, isCRLF );
2255kmime_mk_trivial_ctor_with_name(
Subject, Generics::Unstructured,
Subject )
2258bool Subject::isReply()
const
2260 return asUnicodeString().indexOf( QLatin1String(
"Re:" ), 0, Qt::CaseInsensitive ) == 0;
2265 return HeaderFactory::self()->createHeader( type );
2271 Generics::Unstructured,
Content-Description )
2273 Generics::Unstructured,
Content-Location )
2274kmime_mk_trivial_ctor_with_name(
From, Generics::MailboxList,
From )
2275kmime_mk_trivial_ctor_with_name(
Sender, Generics::SingleMailbox,
Sender )
2276kmime_mk_trivial_ctor_with_name(
To, Generics::AddressList,
To )
2277kmime_mk_trivial_ctor_with_name(
Cc, Generics::AddressList,
Cc )
2278kmime_mk_trivial_ctor_with_name(
Bcc, Generics::AddressList,
Bcc )
2279kmime_mk_trivial_ctor_with_name(
ReplyTo, Generics::AddressList, Reply-
To )
2281kmime_mk_trivial_ctor_with_name(
MIMEVersion, Generics::DotAtom, MIME-Version )
2283kmime_mk_trivial_ctor_with_name(
InReplyTo, Generics::Ident, In-Reply-
To )
2286kmime_mk_trivial_ctor_with_name(
UserAgent, Generics::Unstructured, User-Agent )
A class that encapsulates MIME encoded Content.
Content * parent() const
Returns the parent content object, or 0 if the content doesn't have a parent.
Represents a (email) message.
Represents an (email address, display name) pair according RFC 2822, section 3.4.
void setName(const QString &name)
Sets the name.
QString name() const
Returns the display name.
QString prettyAddress() const
Returns a assembled display name / address string of the following form: "Display Name <address>".
QByteArray as7BitString(const QByteArray &encCharset) const
Returns a 7bit transport encoded representation of this mailbox.
bool hasName() const
Returns true if this mailbox has a display name.
void setAddress(const AddrSpec &addr)
Sets the email address.
QByteArray address() const
Returns a string representation of the email address, without the angle brackets.
This file is part of the API for handling MIME data and defines the Codec class.
This file is part of the API for handling MIME data and defines the Content class.