• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

KMIME Library

kmime_headers.cpp

Go to the documentation of this file.
00001 /*  -*- c++ -*-
00002     kmime_headers.cpp
00003 
00004     KMime, the KDE internet mail/usenet news message library.
00005     Copyright (c) 2001-2002 the KMime authors.
00006     See file AUTHORS for details
00007     Copyright (c) 2006 Volker Krause <vkrause@kde.org>
00008 
00009     This library is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU Library General Public
00011     License assert published by the Free Software Foundation; either
00012     version 2 of the License, or (at your option) any later version.
00013 
00014     This library is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017     Library General Public License for morbe details.
00018 
00019     You should have received a copy of the GNU Library General Public License
00020     along with this library; see the file COPYING.LIB.  If not, write to
00021     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00022     Boston, MA 02110-1301, USA.
00023 */
00040 #include "kmime_headers.h"
00041 #include "kmime_headers_p.h"
00042 
00043 #include "kmime_util.h"
00044 #include "kmime_content.h"
00045 #include "kmime_codecs.h"
00046 #include "kmime_header_parsing.h"
00047 #include "kmime_warning.h"
00048 
00049 #include <QtCore/QTextCodec>
00050 #include <QtCore/QString>
00051 #include <QtCore/QStringList>
00052 
00053 #include <kglobal.h>
00054 #include <kcharsets.h>
00055 
00056 #include <assert.h>
00057 #include <ctype.h>
00058 
00059 // macro to generate a default constructor implementation
00060 #define kmime_mk_trivial_ctor( subclass, baseclass )                  \
00061 subclass::subclass( Content *parent ) : baseclass( parent )           \
00062 {                                                                     \
00063   clear();                                                            \
00064 }                                                                     \
00065                                                                       \
00066 subclass::subclass( Content *parent, const QByteArray &s ) : baseclass( parent ) \
00067 {                                                                     \
00068   from7BitString( s );                                                \
00069 }                                                                     \
00070                                                                       \
00071 subclass::subclass( Content *parent, const QString &s, const QByteArray &charset ) : \
00072   baseclass( parent )                                                 \
00073 {                                                                     \
00074   fromUnicodeString( s, charset );                                    \
00075 }                                                                     \
00076                                                                       \
00077 subclass::~subclass() {}
00078 
00079 
00080 #define kmime_mk_trivial_ctor_with_dptr( subclass, baseclass ) \
00081 subclass::subclass( Content *parent ) : baseclass( new subclass##Private, parent ) \
00082 {                                                                     \
00083   clear();                                                            \
00084 }                                                                     \
00085                                                                       \
00086 subclass::subclass( Content *parent, const QByteArray &s ) : baseclass( new subclass##Private, parent ) \
00087 {                                                                     \
00088   from7BitString( s );                                                \
00089 }                                                                     \
00090                                                                       \
00091 subclass::subclass( Content *parent, const QString &s, const QByteArray &charset ) : \
00092   baseclass( new subclass##Private, parent )                          \
00093 {                                                                     \
00094   fromUnicodeString( s, charset );                                    \
00095 }                                                                     \
00096                                                                       \
00097 subclass::~subclass() {}
00098 
00099 #define kmime_mk_trivial_ctor_with_name( subclass, baseclass, name )  \
00100 kmime_mk_trivial_ctor( subclass, baseclass )                          \
00101                                                                       \
00102 const char *subclass::type() const                                    \
00103 {                                                                     \
00104   return #name;                                                       \
00105 }
00106 
00107 #define kmime_mk_trivial_ctor_with_name_and_dptr( subclass, baseclass, name ) \
00108 kmime_mk_trivial_ctor_with_dptr( subclass, baseclass ) \
00109 const char *subclass::type() const { return #name; }
00110 
00111 #define kmime_mk_dptr_ctor( subclass, baseclass ) \
00112 subclass::subclass( subclass##Private *d, KMime::Content *parent ) : baseclass( d, parent ) {}
00113 
00114 using namespace KMime;
00115 using namespace KMime::Headers;
00116 using namespace KMime::Types;
00117 using namespace KMime::HeaderParsing;
00118 
00119 namespace KMime {
00120 namespace Headers {
00121 //-----<Base>----------------------------------
00122 Base::Base( KMime::Content *parent ) :
00123     d_ptr( new BasePrivate )
00124 {
00125   Q_D(Base);
00126   d->parent = parent;
00127 }
00128 
00129 Base::Base( BasePrivate *dd, KMime::Content *parent ) :
00130     d_ptr( dd )
00131 {
00132   Q_D(Base);
00133   d->parent = parent;
00134 }
00135 
00136 Base::~Base()
00137 {
00138   delete d_ptr;
00139 }
00140 
00141 KMime::Content *Base::parent() const
00142 {
00143   return d_ptr->parent;
00144 }
00145 
00146 void Base::setParent( KMime::Content *parent )
00147 {
00148   d_ptr->parent = parent;
00149 }
00150 
00151 QByteArray Base::rfc2047Charset() const
00152 {
00153   if ( d_ptr->encCS.isEmpty() || forceDefaultCharset() ) {
00154     return defaultCharset();
00155   } else {
00156     return d_ptr->encCS;
00157   }
00158 }
00159 
00160 void Base::setRFC2047Charset( const QByteArray &cs )
00161 {
00162   d_ptr->encCS = cachedCharset( cs );
00163 }
00164 
00165 bool Base::forceDefaultCharset() const
00166 {
00167   return ( parent() != 0 ? parent()->forceDefaultCharset() : false );
00168 }
00169 
00170 QByteArray Base::defaultCharset() const
00171 {
00172   return ( parent() != 0 ? parent()->defaultCharset() : Latin1 );
00173 }
00174 
00175 const char *Base::type() const
00176 {
00177   return "";
00178 }
00179 
00180 bool Base::is( const char *t ) const
00181 {
00182   return strcasecmp( t, type() ) == 0;
00183 }
00184 
00185 bool Base::isMimeHeader() const
00186 {
00187   return strncasecmp( type(), "Content-", 8 ) == 0;
00188 }
00189 
00190 bool Base::isXHeader() const
00191 {
00192   return strncmp( type(), "X-", 2 ) == 0;
00193 }
00194 
00195 QByteArray Base::typeIntro() const
00196 {
00197   return QByteArray( type() ) + ": ";
00198 }
00199 
00200 //-----</Base>---------------------------------
00201 
00202 namespace Generics {
00203 
00204 //-----<Unstructured>-------------------------
00205 
00206 //@cond PRIVATE
00207 kmime_mk_dptr_ctor( Unstructured, Base )
00208 //@endcond
00209 
00210 Unstructured::Unstructured( Content *p ) : Base( new UnstructuredPrivate, p )
00211 {
00212 }
00213 
00214 Unstructured::Unstructured( Content *p, const QByteArray &s ) : Base( new UnstructuredPrivate, p )
00215 {
00216   from7BitString( s );
00217 }
00218 
00219 Unstructured::Unstructured( Content *p, const QString &s, const QByteArray &cs ) : Base( new UnstructuredPrivate, p )
00220 {
00221   fromUnicodeString( s, cs );
00222 }
00223 
00224 Unstructured::~Unstructured()
00225 {
00226 }
00227 
00228 void Unstructured::from7BitString( const QByteArray &s )
00229 {
00230   Q_D(Unstructured);
00231   d->decoded = decodeRFC2047String( s, d->encCS, defaultCharset(), forceDefaultCharset() );
00232 }
00233 
00234 QByteArray Unstructured::as7BitString( bool withHeaderType ) const
00235 {
00236   const Q_D(Unstructured);
00237   QByteArray result;
00238   if ( withHeaderType ) {
00239     result = typeIntro();
00240   }
00241   result += encodeRFC2047String( d->decoded, d->encCS ) ;
00242 
00243   return result;
00244 }
00245 
00246 void Unstructured::fromUnicodeString( const QString &s, const QByteArray &b )
00247 {
00248   Q_D(Unstructured);
00249   d->decoded = s;
00250   d->encCS = cachedCharset( b );
00251 }
00252 
00253 QString Unstructured::asUnicodeString() const
00254 {
00255   return d_func()->decoded;
00256 }
00257 
00258 void Unstructured::clear()
00259 {
00260   Q_D(Unstructured);
00261   d->decoded.truncate( 0 );
00262 }
00263 
00264 bool Unstructured::isEmpty() const
00265 {
00266   return d_func()->decoded.isEmpty();
00267 }
00268 
00269 //-----</Unstructured>-------------------------
00270 
00271 //-----<Structured>-------------------------
00272 
00273 Structured::Structured( Content *p ) : Base( new StructuredPrivate, p )
00274 {
00275 }
00276 
00277 Structured::Structured( Content *p, const QByteArray &s ) : Base( new StructuredPrivate, p )
00278 {
00279   from7BitString( s );
00280 }
00281 
00282 Structured::Structured( Content *p, const QString &s, const QByteArray &cs ) : Base( new StructuredPrivate, p )
00283 {
00284   fromUnicodeString( s, cs );
00285 }
00286 
00287 kmime_mk_dptr_ctor( Structured, Base )
00288 
00289 Structured::~Structured()
00290 {
00291 }
00292 
00293 void Structured::from7BitString( const QByteArray &s )
00294 {
00295   Q_D(Structured);
00296   if ( d->encCS.isEmpty() ) {
00297     d->encCS = defaultCharset();
00298   }
00299   const char *cursor = s.constData();
00300   parse( cursor, cursor + s.length() );
00301 }
00302 
00303 QString Structured::asUnicodeString() const
00304 {
00305   return QString::fromLatin1( as7BitString( false ) );
00306 }
00307 
00308 void Structured::fromUnicodeString( const QString &s, const QByteArray &b )
00309 {
00310   Q_D(Structured);
00311   d->encCS = cachedCharset( b );
00312   from7BitString( s.toLatin1() );
00313 }
00314 
00315 //-----</Structured>-------------------------
00316 
00317 //-----<Address>-------------------------
00318 
00319 Address::Address( Content *p ) : Structured( new AddressPrivate, p )
00320 {
00321 }
00322 
00323 Address::Address( Content *p, const QByteArray &s ) : Structured( new AddressPrivate, p )
00324 {
00325   from7BitString( s );
00326 }
00327 
00328 Address::Address( Content *p, const QString &s, const QByteArray &cs ) : Structured( new AddressPrivate, p )
00329 {
00330   fromUnicodeString( s, cs );
00331 }
00332 
00333 kmime_mk_dptr_ctor( Address, Structured )
00334 
00335 Address:: ~Address()
00336 {
00337 }
00338 
00339 // helper method used in AddressList and MailboxList
00340 static bool stringToMailbox( const QByteArray &address,
00341                              const QString &displayName, Types::Mailbox &mbox )
00342 {
00343   Types::AddrSpec addrSpec;
00344   mbox.setName( displayName );
00345   const char *cursor = address.constData();
00346   if ( !parseAngleAddr( cursor, cursor + address.length(), addrSpec ) ) {
00347     if ( !parseAddrSpec( cursor, cursor + address.length(), addrSpec ) ) {
00348       kWarning() << "Invalid address";
00349       return false;
00350     }
00351   }
00352   mbox.setAddress( addrSpec );
00353   return true;
00354 }
00355 
00356 //-----</Address>-------------------------
00357 
00358 //-----<MailboxList>-------------------------
00359 
00360 kmime_mk_trivial_ctor_with_dptr( MailboxList, Address )
00361 kmime_mk_dptr_ctor( MailboxList, Address )
00362 
00363 QByteArray MailboxList::as7BitString( bool withHeaderType ) const
00364 {
00365   const Q_D(MailboxList);
00366   if ( isEmpty() ) {
00367     return QByteArray();
00368   }
00369 
00370   QByteArray rv;
00371   if ( withHeaderType ) {
00372     rv = typeIntro();
00373   }
00374   foreach ( Types::Mailbox mbox, d->mailboxList ) {
00375     rv += mbox.as7BitString( d->encCS );
00376     rv += ", ";
00377   }
00378   rv.resize( rv.length() - 2 );
00379   return rv;
00380 }
00381 
00382 void MailboxList::fromUnicodeString( const QString &s, const QByteArray &b )
00383 {
00384   Q_D(MailboxList);
00385   d->encCS = cachedCharset( b );
00386   from7BitString( encodeRFC2047String( s, b, false ) );
00387 }
00388 
00389 QString MailboxList::asUnicodeString() const
00390 {
00391   return prettyAddresses().join( QLatin1String( ", " ) );
00392 }
00393 
00394 void MailboxList::clear()
00395 {
00396   Q_D(MailboxList);
00397   d->mailboxList.clear();
00398 }
00399 
00400 bool MailboxList::isEmpty() const
00401 {
00402   return d_func()->mailboxList.isEmpty();
00403 }
00404 
00405 void MailboxList::addAddress( const Types::Mailbox &mbox )
00406 {
00407   Q_D(MailboxList);
00408   d->mailboxList.append( mbox );
00409 }
00410 
00411 void MailboxList::addAddress( const QByteArray &address,
00412                               const QString &displayName )
00413 {
00414   Q_D(MailboxList);
00415   Types::Mailbox mbox;
00416   if ( stringToMailbox( address, displayName, mbox ) ) {
00417     d->mailboxList.append( mbox );
00418   }
00419 }
00420 
00421 QList< QByteArray > MailboxList::addresses() const
00422 {
00423   QList<QByteArray> rv;
00424   foreach ( Types::Mailbox mbox, d_func()->mailboxList ) {
00425     rv.append( mbox.address() );
00426   }
00427   return rv;
00428 }
00429 
00430 QStringList MailboxList::displayNames() const
00431 {
00432   QStringList rv;
00433   foreach ( Types::Mailbox mbox, d_func()->mailboxList ) {
00434     rv.append( mbox.name() );
00435   }
00436   return rv;
00437 }
00438 
00439 QStringList MailboxList::prettyAddresses() const
00440 {
00441   QStringList rv;
00442   foreach ( Types::Mailbox mbox, d_func()->mailboxList ) {
00443     rv.append( mbox.prettyAddress() );
00444   }
00445   return rv;
00446 }
00447 
00448 Types::Mailbox::List MailboxList::mailboxes() const
00449 {
00450   return d_func()->mailboxList;
00451 }
00452 
00453 bool MailboxList::parse( const char* &scursor, const char *const send,
00454                          bool isCRLF )
00455 {
00456   Q_D(MailboxList);
00457   // examples:
00458   // from := "From:" mailbox-list CRLF
00459   // sender := "Sender:" mailbox CRLF
00460 
00461   // parse an address-list:
00462   QList<Types::Address> maybeAddressList;
00463   if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) {
00464     return false;
00465   }
00466 
00467   d->mailboxList.clear();
00468 
00469   // extract the mailboxes and complain if there are groups:
00470   QList<Types::Address>::Iterator it;
00471   for ( it = maybeAddressList.begin(); it != maybeAddressList.end() ; ++it ) {
00472     if ( !(*it).displayName.isEmpty() ) {
00473       KMIME_WARN << "mailbox groups in header disallowing them! Name: \""
00474                  << (*it).displayName << "\"" << endl;
00475     }
00476     d->mailboxList += (*it).mailboxList;
00477   }
00478   return true;
00479 }
00480 
00481 //-----</MailboxList>-------------------------
00482 
00483 //-----<SingleMailbox>-------------------------
00484 
00485 //@cond PRIVATE
00486 kmime_mk_trivial_ctor_with_dptr( SingleMailbox, MailboxList )
00487 //@endcond
00488 
00489 bool SingleMailbox::parse( const char* &scursor, const char *const send,
00490                              bool isCRLF )
00491 {
00492   Q_D(MailboxList);
00493   if ( !MailboxList::parse( scursor, send, isCRLF ) ) {
00494     return false;
00495   }
00496 
00497   if ( d->mailboxList.count() > 1 ) {
00498     KMIME_WARN << "multiple mailboxes in header allowing only a single one!"
00499                << endl;
00500   }
00501   return true;
00502 }
00503 
00504 //-----</SingleMailbox>-------------------------
00505 
00506 //-----<AddressList>-------------------------
00507 
00508 //@cond PRIVATE
00509 kmime_mk_trivial_ctor_with_dptr( AddressList, Address )
00510 kmime_mk_dptr_ctor( AddressList, Address )
00511 //@endcond
00512 
00513 QByteArray AddressList::as7BitString( bool withHeaderType ) const
00514 {
00515   const Q_D(AddressList);
00516   if ( d->addressList.isEmpty() ) {
00517     return QByteArray();
00518   }
00519 
00520   QByteArray rv;
00521   if ( withHeaderType ) {
00522     rv = typeIntro();
00523   }
00524   foreach ( Types::Address addr, d->addressList ) {
00525     foreach ( Types::Mailbox mbox, addr.mailboxList ) {
00526       rv += mbox.as7BitString( d->encCS );
00527       rv += ", ";
00528     }
00529   }
00530   rv.resize( rv.length() - 2 );
00531   return rv;
00532 }
00533 
00534 void AddressList::fromUnicodeString( const QString &s, const QByteArray &b )
00535 {
00536   Q_D(AddressList);
00537   d->encCS = cachedCharset( b );
00538   from7BitString( encodeRFC2047String( s, b, false ) );
00539 }
00540 
00541 QString AddressList::asUnicodeString() const
00542 {
00543   return prettyAddresses().join( QLatin1String( ", " ) );
00544 }
00545 
00546 void AddressList::clear()
00547 {
00548   Q_D(AddressList);
00549   d->addressList.clear();
00550 }
00551 
00552 bool AddressList::isEmpty() const
00553 {
00554   return d_func()->addressList.isEmpty();
00555 }
00556 
00557 void AddressList::addAddress( const Types::Mailbox &mbox )
00558 {
00559   Q_D(AddressList);
00560   Types::Address addr;
00561   addr.mailboxList.append( mbox );
00562   d->addressList.append( addr );
00563 }
00564 
00565 void AddressList::addAddress( const QByteArray &address,
00566                               const QString &displayName )
00567 {
00568   Q_D(AddressList);
00569   Types::Address addr;
00570   Types::Mailbox mbox;
00571   if ( stringToMailbox( address, displayName, mbox ) ) {
00572     addr.mailboxList.append( mbox );
00573     d->addressList.append( addr );
00574   }
00575 }
00576 
00577 QList< QByteArray > AddressList::addresses() const
00578 {
00579   QList<QByteArray> rv;
00580   foreach ( Types::Address addr, d_func()->addressList ) {
00581     foreach ( Types::Mailbox mbox, addr.mailboxList ) {
00582       rv.append( mbox.address() );
00583     }
00584   }
00585   return rv;
00586 }
00587 
00588 QStringList AddressList::displayNames() const
00589 {
00590   QStringList rv;
00591   foreach ( Types::Address addr, d_func()->addressList ) {
00592     foreach ( Types::Mailbox mbox, addr.mailboxList ) {
00593       rv.append( mbox.name() );
00594     }
00595   }
00596   return rv;
00597 }
00598 
00599 QStringList AddressList::prettyAddresses() const
00600 {
00601   QStringList rv;
00602   foreach ( Types::Address addr, d_func()->addressList ) {
00603     foreach ( Types::Mailbox mbox, addr.mailboxList ) {
00604       rv.append( mbox.prettyAddress() );
00605     }
00606   }
00607   return rv;
00608 }
00609 
00610 Types::Mailbox::List AddressList::mailboxes() const
00611 {
00612   Types::Mailbox::List rv;
00613   foreach ( Types::Address addr, d_func()->addressList ) {
00614     foreach ( Types::Mailbox mbox, addr.mailboxList ) {
00615       rv.append( mbox );
00616     }
00617   }
00618   return rv;
00619 }
00620 
00621 bool AddressList::parse( const char* &scursor, const char *const send,
00622                          bool isCRLF )
00623 {
00624   Q_D(AddressList);
00625   QList<Types::Address> maybeAddressList;
00626   if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) {
00627     return false;
00628   }
00629 
00630   d->addressList = maybeAddressList;
00631   return true;
00632 }
00633 
00634 //-----</AddressList>-------------------------
00635 
00636 //-----<Token>-------------------------
00637 
00638 //@cond PRIVATE
00639 kmime_mk_trivial_ctor_with_dptr( Token, Structured )
00640 kmime_mk_dptr_ctor( Token, Structured )
00641 //@endcond
00642 
00643 QByteArray Token::as7BitString( bool withHeaderType ) const
00644 {
00645   if ( isEmpty() ) {
00646     return QByteArray();
00647   }
00648   if ( withHeaderType ) {
00649     return typeIntro() + d_func()->token;
00650   }
00651   return d_func()->token;
00652 }
00653 
00654 void Token::clear()
00655 {
00656   Q_D(Token);
00657   d->token.clear();
00658 }
00659 
00660 bool Token::isEmpty() const
00661 {
00662   return d_func()->token.isEmpty();
00663 }
00664 
00665 QByteArray Token::token() const
00666 {
00667   return d_func()->token;
00668 }
00669 
00670 void Token::setToken( const QByteArray &t )
00671 {
00672   Q_D(Token);
00673   d->token = t;
00674 }
00675 
00676 bool Token::parse( const char* &scursor, const char *const send, bool isCRLF )
00677 {
00678   Q_D(Token);
00679   clear();
00680   eatCFWS( scursor, send, isCRLF );
00681   // must not be empty:
00682   if ( scursor == send ) {
00683     return false;
00684   }
00685 
00686   QPair<const char*,int> maybeToken;
00687   if ( !parseToken( scursor, send, maybeToken, false /* no 8bit chars */ ) ) {
00688     return false;
00689   }
00690   d->token = QByteArray( maybeToken.first, maybeToken.second );
00691 
00692   // complain if trailing garbage is found:
00693   eatCFWS( scursor, send, isCRLF );
00694   if ( scursor != send ) {
00695     KMIME_WARN << "trailing garbage after token in header allowing "
00696       "only a single token!" << endl;
00697   }
00698   return true;
00699 }
00700 
00701 //-----</Token>-------------------------
00702 
00703 //-----<PhraseList>-------------------------
00704 
00705 //@cond PRIVATE
00706 kmime_mk_trivial_ctor_with_dptr( PhraseList, Structured )
00707 //@endcond
00708 
00709 QByteArray PhraseList::as7BitString( bool withHeaderType ) const
00710 {
00711   const Q_D(PhraseList);
00712   if ( isEmpty() ) {
00713     return QByteArray();
00714   }
00715 
00716   QByteArray rv;
00717   if ( withHeaderType ) {
00718     rv = typeIntro();
00719   }
00720 
00721   for ( int i = 0; i < d->phraseList.count(); ++i ) {
00722     // FIXME: only encode when needed, quote when needed, etc.
00723     rv += encodeRFC2047String( d->phraseList[i], d->encCS, false, false );
00724     if ( i != d->phraseList.count() - 1 ) {
00725       rv += ", ";
00726     }
00727   }
00728 
00729   return rv;
00730 }
00731 
00732 QString PhraseList::asUnicodeString() const
00733 {
00734   return d_func()->phraseList.join( QLatin1String( ", " ) );
00735 }
00736 
00737 void PhraseList::clear()
00738 {
00739   Q_D(PhraseList);
00740   d->phraseList.clear();
00741 }
00742 
00743 bool PhraseList::isEmpty() const
00744 {
00745   return d_func()->phraseList.isEmpty();
00746 }
00747 
00748 QStringList PhraseList::phrases() const
00749 {
00750   return d_func()->phraseList;
00751 }
00752 
00753 bool PhraseList::parse( const char* &scursor, const char *const send,
00754                          bool isCRLF )
00755 {
00756   Q_D(PhraseList);
00757   d->phraseList.clear();
00758 
00759   while ( scursor != send ) {
00760     eatCFWS( scursor, send, isCRLF );
00761     // empty entry ending the list: OK.
00762     if ( scursor == send ) {
00763       return true;
00764     }
00765     // empty entry: ignore.
00766     if ( *scursor == ',' ) {
00767       scursor++;
00768       continue;
00769     }
00770 
00771     QString maybePhrase;
00772     if ( !parsePhrase( scursor, send, maybePhrase, isCRLF ) ) {
00773       return false;
00774     }
00775     d->phraseList.append( maybePhrase );
00776 
00777     eatCFWS( scursor, send, isCRLF );
00778     // non-empty entry ending the list: OK.
00779     if ( scursor == send ) {
00780       return true;
00781     }
00782     // comma separating the phrases: eat.
00783     if ( *scursor == ',' ) {
00784       scursor++;
00785     }
00786   }
00787   return true;
00788 }
00789 
00790 //-----</PhraseList>-------------------------
00791 
00792 //-----<DotAtom>-------------------------
00793 
00794 //@cond PRIVATE
00795 kmime_mk_trivial_ctor_with_dptr( DotAtom, Structured )
00796 //@endcond
00797 
00798 QByteArray DotAtom::as7BitString( bool withHeaderType ) const
00799 {
00800   if ( isEmpty() ) {
00801     return QByteArray();
00802   }
00803 
00804   QByteArray rv;
00805   if ( withHeaderType ) {
00806     rv += typeIntro();
00807   }
00808 
00809   rv += d_func()->dotAtom.toLatin1(); // FIXME: encoding?
00810   return rv;
00811 }
00812 
00813 QString DotAtom::asUnicodeString() const
00814 {
00815   return d_func()->dotAtom;
00816 }
00817 
00818 void DotAtom::clear()
00819 {
00820   Q_D(DotAtom);
00821   d->dotAtom.clear();
00822 }
00823 
00824 bool DotAtom::isEmpty() const
00825 {
00826   return d_func()->dotAtom.isEmpty();
00827 }
00828 
00829 bool DotAtom::parse( const char* &scursor, const char *const send,
00830                       bool isCRLF )
00831 {
00832   Q_D(DotAtom);
00833   QString maybeDotAtom;
00834   if ( !parseDotAtom( scursor, send, maybeDotAtom, isCRLF ) ) {
00835     return false;
00836   }
00837 
00838   d->dotAtom = maybeDotAtom;
00839 
00840   eatCFWS( scursor, send, isCRLF );
00841   if ( scursor != send ) {
00842     KMIME_WARN << "trailing garbage after dot-atom in header allowing "
00843       "only a single dot-atom!" << endl;
00844   }
00845   return true;
00846 }
00847 
00848 //-----</DotAtom>-------------------------
00849 
00850 //-----<Parametrized>-------------------------
00851 
00852 //@cond PRIVATE
00853 kmime_mk_trivial_ctor_with_dptr( Parametrized, Structured )
00854 kmime_mk_dptr_ctor( Parametrized, Structured )
00855 //@endcond
00856 
00857 QByteArray Parametrized::as7BitString( bool withHeaderType ) const
00858 {
00859   const Q_D(Parametrized);
00860   if ( isEmpty() ) {
00861     return QByteArray();
00862   }
00863 
00864   QByteArray rv;
00865   if ( withHeaderType ) {
00866     rv += typeIntro();
00867   }
00868 
00869   bool first = true;
00870   for ( QMap<QString,QString>::ConstIterator it = d->parameterHash.constBegin();
00871         it != d->parameterHash.constEnd(); ++it )
00872   {
00873     if ( !first ) {
00874       rv += "; ";
00875     } else {
00876       first = false;
00877     }
00878     rv += it.key().toLatin1() + '=';
00879     if ( isUsAscii( it.value() ) ) {
00880       QByteArray tmp = it.value().toLatin1();
00881       addQuotes( tmp, true ); // force quoting, eg. for whitespaces in parameter value
00882       rv += tmp;
00883     } else {
00884       // FIXME: encoded strings are not allowed inside quotes, OTOH we need to quote whitespaces...
00885       rv += "\"" + encodeRFC2047String( it.value(), d->encCS ) + "\"";
00886     }
00887   }
00888 
00889   return rv;
00890 }
00891 
00892 QString Parametrized::parameter( const QString &key ) const
00893 {
00894   return d_func()->parameterHash.value( key );
00895 }
00896 
00897 void Parametrized::setParameter( const QString &key, const QString &value )
00898 {
00899   Q_D(Parametrized);
00900   d->parameterHash.insert( key, value );
00901 }
00902 
00903 bool Parametrized::isEmpty() const
00904 {
00905   return d_func()->parameterHash.isEmpty();
00906 }
00907 
00908 void Parametrized::clear()
00909 {
00910   Q_D(Parametrized);
00911   d->parameterHash.clear();
00912 }
00913 
00914 bool Parametrized::parse( const char *& scursor, const char * const send,
00915                           bool isCRLF )
00916 {
00917   Q_D(Parametrized);
00918   d->parameterHash.clear();
00919   if ( !parseParameterList( scursor, send, d->parameterHash, isCRLF ) ) {
00920     return false;
00921   }
00922   return true;
00923 }
00924 
00925 //-----</Parametrized>-------------------------
00926 
00927 //-----<Ident>-------------------------
00928 
00929 //@cond PRIVATE
00930 kmime_mk_trivial_ctor_with_dptr( Ident, Address )
00931 kmime_mk_dptr_ctor( Ident, Address )
00932 //@endcond
00933 
00934 QByteArray Ident::as7BitString( bool withHeaderType ) const
00935 {
00936   const Q_D(Ident);
00937   if ( d->msgIdList.isEmpty() ) {
00938     return QByteArray();
00939   }
00940 
00941   QByteArray rv;
00942   if ( withHeaderType ) {
00943     rv = typeIntro();
00944   }
00945   foreach ( Types::AddrSpec addr, d->msgIdList ) {
00946     rv += '<';
00947     rv += addr.asString().toLatin1(); // FIXME: change parsing to use QByteArrays
00948     rv += "> ";
00949   }
00950   rv.resize( rv.length() - 1 );
00951   return rv;
00952 }
00953 
00954 void Ident::clear()
00955 {
00956   Q_D(Ident);
00957   d->msgIdList.clear();
00958 }
00959 
00960 bool Ident::isEmpty() const
00961 {
00962   return d_func()->msgIdList.isEmpty();
00963 }
00964 
00965 bool Ident::parse( const char* &scursor, const char * const send, bool isCRLF )
00966 {
00967   Q_D(Ident);
00968   // msg-id   := "<" id-left "@" id-right ">"
00969   // id-left  := dot-atom-text / no-fold-quote / local-part
00970   // id-right := dot-atom-text / no-fold-literal / domain
00971   //
00972   // equivalent to:
00973   // msg-id   := angle-addr
00974 
00975   d->msgIdList.clear();
00976 
00977   while ( scursor != send ) {
00978     eatCFWS( scursor, send, isCRLF );
00979     // empty entry ending the list: OK.
00980     if ( scursor == send ) {
00981       return true;
00982     }
00983     // empty entry: ignore.
00984     if ( *scursor == ',' ) {
00985       scursor++;
00986       continue;
00987     }
00988 
00989     AddrSpec maybeMsgId;
00990     if ( !parseAngleAddr( scursor, send, maybeMsgId, isCRLF ) ) {
00991       return false;
00992     }
00993     d->msgIdList.append( maybeMsgId );
00994 
00995     eatCFWS( scursor, send, isCRLF );
00996     // header end ending the list: OK.
00997     if ( scursor == send ) {
00998       return true;
00999     }
01000     // regular item separator: eat it.
01001     if ( *scursor == ',' ) {
01002       scursor++;
01003     }
01004   }
01005   return true;
01006 }
01007 
01008 QList<QByteArray> Ident::identifiers() const
01009 {
01010   QList<QByteArray> rv;
01011   foreach ( Types::AddrSpec addr, d_func()->msgIdList ) {
01012     rv.append( addr.asString().toLatin1() ); // FIXME change parsing to create QByteArrays
01013   }
01014   return rv;
01015 }
01016 
01017 void Ident::appendIdentifier( const QByteArray &id )
01018 {
01019   Q_D(Ident);
01020   QByteArray tmp = id;
01021   if ( !tmp.startsWith( '<' ) ) {
01022     tmp.prepend( '<' );
01023   }
01024   if ( !tmp.endsWith( '>' ) ) {
01025     tmp.append( '>' );
01026   }
01027   AddrSpec msgId;
01028   const char *cursor = tmp.constData();
01029   if ( parseAngleAddr( cursor, cursor + tmp.length(), msgId ) ) {
01030     d->msgIdList.append( msgId );
01031   } else {
01032     kWarning() << "Unable to parse address spec!";
01033   }
01034 }
01035 
01036 //-----</Ident>-------------------------
01037 
01038 //-----<SingleIdent>-------------------------
01039 
01040 //@cond PRIVATE
01041 kmime_mk_trivial_ctor_with_dptr( SingleIdent, Ident )
01042 //@endcond
01043 
01044 QByteArray SingleIdent::identifier() const
01045 {
01046   if ( d_func()->msgIdList.isEmpty() ) {
01047     return QByteArray();
01048   }
01049   return identifiers().first();
01050 }
01051 
01052 void SingleIdent::setIdentifier( const QByteArray &id )
01053 {
01054   Q_D(SingleIdent);
01055   d->msgIdList.clear();
01056   appendIdentifier( id );
01057 }
01058 
01059 bool SingleIdent::parse( const char* &scursor, const char * const send,
01060                          bool isCRLF )
01061 {
01062   Q_D(SingleIdent);
01063   if ( !Ident::parse( scursor, send, isCRLF ) ) {
01064     return false;
01065   }
01066 
01067   if ( d->msgIdList.count() > 1 ) {
01068     KMIME_WARN << "more than one msg-id in header "
01069                << "allowing only a single one!" << endl;
01070   }
01071   return true;
01072 }
01073 
01074 //-----</SingleIdent>-------------------------
01075 
01076 } // namespace Generics
01077 
01078 //-----<ReturnPath>-------------------------
01079 
01080 //@cond PRIVATE
01081 kmime_mk_trivial_ctor_with_name_and_dptr( ReturnPath, Generics::Address, Return-Path )
01082 //@endcond
01083 
01084 QByteArray ReturnPath::as7BitString( bool withHeaderType ) const
01085 {
01086   if ( isEmpty() ) {
01087     return QByteArray();
01088   }
01089 
01090   QByteArray rv;
01091   if ( withHeaderType ) {
01092     rv += typeIntro();
01093   }
01094   rv += '<' + d_func()->mailbox.as7BitString( d_func()->encCS ) + '>';
01095   return rv;
01096 }
01097 
01098 void ReturnPath::clear()
01099 {
01100   Q_D(ReturnPath);
01101   d->mailbox.setAddress( Types::AddrSpec() );
01102   d->mailbox.setName( QString() );
01103 }
01104 
01105 bool ReturnPath::isEmpty() const
01106 {
01107   const Q_D(ReturnPath);
01108   return !d->mailbox.hasAddress() && !d->mailbox.hasName();
01109 }
01110 
01111 bool ReturnPath::parse( const char* &scursor, const char * const send,
01112                         bool isCRLF )
01113 {
01114   Q_D(ReturnPath);
01115   eatCFWS( scursor, send, isCRLF );
01116   if ( scursor == send ) {
01117     return false;
01118   }
01119 
01120   const char * oldscursor = scursor;
01121 
01122   Mailbox maybeMailbox;
01123   if ( !parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) {
01124     // mailbox parsing failed, but check for empty brackets:
01125     scursor = oldscursor;
01126     if ( *scursor != '<' ) {
01127       return false;
01128     }
01129     scursor++;
01130     eatCFWS( scursor, send, isCRLF );
01131     if ( scursor == send || *scursor != '>' ) {
01132       return false;
01133     }
01134     scursor++;
01135 
01136     // prepare a Null mailbox:
01137     AddrSpec emptyAddrSpec;
01138     maybeMailbox.setName( QString() );
01139     maybeMailbox.setAddress( emptyAddrSpec );
01140   } else {
01141     // check that there was no display-name:
01142     if ( maybeMailbox.hasName() ) {
01143       KMIME_WARN << "display-name \"" << maybeMailbox.name()
01144                  << "\" in Return-Path!" << endl;
01145     }
01146   }
01147   d->mailbox = maybeMailbox;
01148 
01149   // see if that was all:
01150   eatCFWS( scursor, send, isCRLF );
01151   // and warn if it wasn't:
01152   if ( scursor != send ) {
01153     KMIME_WARN << "trailing garbage after angle-addr in Return-Path!" << endl;
01154   }
01155   return true;
01156 }
01157 
01158 //-----</ReturnPath>-------------------------
01159 
01160 //-----<Generic>-------------------------------
01161 
01162 Generic::Generic() : Generics::Unstructured( new GenericPrivate )
01163 {
01164 }
01165 
01166 Generic::Generic( const char *t ) : Generics::Unstructured( new GenericPrivate )
01167 {
01168   setType( t );
01169 }
01170 
01171 Generic::Generic( const char *t, Content *p )
01172   : Generics::Unstructured( new GenericPrivate, p )
01173 {
01174   setType( t );
01175 }
01176 
01177 Generic::Generic( const char *t, Content *p, const QByteArray &s )
01178   : Generics::Unstructured( new GenericPrivate, p )
01179 {
01180   from7BitString( s );
01181   setType( t );
01182 }
01183 
01184 Generic::Generic( const char *t, Content *p, const QString &s, const QByteArray &cs )
01185   : Generics::Unstructured( new GenericPrivate, p )
01186 {
01187   fromUnicodeString( s, cs );
01188   setType( t );
01189 }
01190 
01191 Generic::~Generic()
01192 {
01193 }
01194 
01195 void Generic::clear()
01196 {
01197   Q_D(Generic);
01198   delete[] d->type;
01199   d->type = 0;
01200   Unstructured::clear();
01201 }
01202 
01203 bool Generic::isEmpty() const
01204 {
01205   return d_func()->type == 0 || Unstructured::isEmpty();
01206 }
01207 
01208 const char *Generic::type() const
01209 {
01210   return d_func()->type;
01211 }
01212 
01213 void Generic::setType( const char *type )
01214 {
01215   Q_D(Generic);
01216   if ( d->type ) {
01217     delete[] d->type;
01218   }
01219   if ( type ) {
01220     d->type = new char[strlen( type )+1];
01221     strcpy( d->type, type );
01222   } else {
01223     d->type = 0;
01224   }
01225 }
01226 
01227 //-----<Generic>-------------------------------
01228 
01229 //-----<MessageID>-----------------------------
01230 
01231 //@cond PRIVATE
01232 kmime_mk_trivial_ctor_with_name( MessageID, Generics::SingleIdent, Message-Id )
01233 //@endcond
01234 
01235 void MessageID::generate( const QByteArray &fqdn )
01236 {
01237   setIdentifier( uniqueString() + '@' + fqdn + '>' );
01238 }
01239 
01240 //-----</MessageID>----------------------------
01241 
01242 //-----<Control>-------------------------------
01243 
01244 //@cond PRIVATE
01245 kmime_mk_trivial_ctor_with_name_and_dptr( Control, Generics::Structured, Control )
01246 //@endcond
01247 
01248 QByteArray Control::as7BitString( bool withHeaderType ) const
01249 {
01250   const Q_D(Control);
01251   if ( isEmpty() ) {
01252     return QByteArray();
01253   }
01254 
01255   QByteArray rv;
01256   if ( withHeaderType ) {
01257     rv += typeIntro();
01258   }
01259 
01260   rv += d->name;
01261   if ( !d->parameter.isEmpty() ) {
01262     rv += ' ' + d->parameter;
01263   }
01264   return rv;
01265 }
01266 
01267 void Control::clear()
01268 {
01269   Q_D(Control);
01270   d->name.clear();
01271   d->parameter.clear();
01272 }
01273 
01274 bool Control::isEmpty() const
01275 {
01276   return d_func()->name.isEmpty();
01277 }
01278 
01279 QByteArray Control::controlType() const
01280 {
01281   return d_func()->name;
01282 }
01283 
01284 QByteArray Control::parameter() const
01285 {
01286   return d_func()->parameter;
01287 }
01288 
01289 bool Control::isCancel() const
01290 {
01291   return d_func()->name.toLower() == "cancel";
01292 }
01293 
01294 void Control::setCancel( const QByteArray &msgid )
01295 {
01296   Q_D(Control);
01297   d->name = "cancel";
01298   d->parameter = msgid;
01299 }
01300 
01301 bool Control::parse( const char* &scursor, const char *const send, bool isCRLF )
01302 {
01303   Q_D(Control);
01304   clear();
01305   eatCFWS( scursor, send, isCRLF );
01306   if ( scursor == send ) {
01307     return false;
01308   }
01309   const char *start = scursor;
01310   while ( scursor != send && !isspace( *scursor ) ) {
01311     ++scursor;
01312   }
01313   d->name = QByteArray( start, scursor - start );
01314   eatCFWS( scursor, send, isCRLF );
01315   d->parameter = QByteArray( scursor, send - scursor );
01316   return true;
01317 }
01318 
01319 //-----</Control>------------------------------
01320 
01321 //-----<MailCopiesTo>--------------------------
01322 
01323 //@cond PRIVATE
01324 kmime_mk_trivial_ctor_with_name_and_dptr( MailCopiesTo,
01325                                  Generics::AddressList, Mail-Copies-To )
01326 //@endcond
01327 
01328 QByteArray MailCopiesTo::as7BitString( bool withHeaderType ) const
01329 {
01330   QByteArray rv;
01331   if ( withHeaderType ) {
01332     rv += typeIntro();
01333   }
01334   if ( !AddressList::isEmpty() ) {
01335     rv += AddressList::as7BitString( false );
01336   } else {
01337     if ( d_func()->alwaysCopy ) {
01338       rv += "poster";
01339     } else if ( d_func()->neverCopy ) {
01340       rv += "nobody";
01341     }
01342   }
01343   return rv;
01344 }
01345 
01346 QString MailCopiesTo::asUnicodeString() const
01347 {
01348   if ( !AddressList::isEmpty() ) {
01349     return AddressList::asUnicodeString();
01350   }
01351   if ( d_func()->alwaysCopy ) {
01352     return QLatin1String( "poster" );
01353   }
01354   if ( d_func()->neverCopy ) {
01355     return QLatin1String( "nobody" );
01356   }
01357   return QString();
01358 }
01359 
01360 void MailCopiesTo::clear()
01361 {
01362   Q_D(MailCopiesTo);
01363   AddressList::clear();
01364   d->alwaysCopy = false;
01365   d->neverCopy = false;
01366 }
01367 
01368 bool MailCopiesTo::isEmpty() const
01369 {
01370   return AddressList::isEmpty() && !(d_func()->alwaysCopy || d_func()->neverCopy);
01371 }
01372 
01373 bool MailCopiesTo::alwaysCopy() const
01374 {
01375   return !AddressList::isEmpty() || d_func()->alwaysCopy;
01376 }
01377 
01378 void MailCopiesTo::setAlwaysCopy()
01379 {
01380   Q_D(MailCopiesTo);
01381   clear();
01382   d->alwaysCopy = true;
01383 }
01384 
01385 bool MailCopiesTo::neverCopy() const
01386 {
01387   return d_func()->neverCopy;
01388 }
01389 
01390 void MailCopiesTo::setNeverCopy()
01391 {
01392   Q_D(MailCopiesTo);
01393   clear();
01394   d->neverCopy = true;
01395 }
01396 
01397 bool MailCopiesTo::parse( const char *& scursor, const char * const send,
01398                           bool isCRLF )
01399 {
01400   Q_D(MailCopiesTo);
01401   clear();
01402   if ( send - scursor == 5 ) {
01403     if ( qstrnicmp( "never", scursor, 5 ) == 0 ) {
01404       d->neverCopy = true;
01405       return true;
01406     }
01407   }
01408   if ( send - scursor == 6 ) {
01409     if ( qstrnicmp( "always", scursor, 6 ) == 0 || qstrnicmp( "poster", scursor, 6 ) == 0 ) {
01410       d->alwaysCopy = true;
01411       return true;
01412     }
01413     if ( qstrnicmp( "nobody", scursor, 6 ) == 0 ) {
01414       d->alwaysCopy = true;
01415       return true;
01416     }
01417   }
01418   return AddressList::parse( scursor, send, isCRLF );
01419 }
01420 
01421 //-----</MailCopiesTo>-------------------------
01422 
01423 //-----<Date>----------------------------------
01424 
01425 //@cond PRIVATE
01426 kmime_mk_trivial_ctor_with_name_and_dptr( Date, Generics::Structured, Date )
01427 //@endcond
01428 
01429 QByteArray Date::as7BitString( bool withHeaderType ) const
01430 {
01431   if ( isEmpty() ) {
01432     return QByteArray();
01433   }
01434 
01435   QByteArray rv;
01436   if ( withHeaderType ) {
01437     rv += typeIntro();
01438   }
01439   rv += d_func()->dateTime.toString( KDateTime::RFCDateDay ).toLatin1();
01440   return rv;
01441 }
01442 
01443 void Date::clear()
01444 {
01445   Q_D(Date);
01446   d->dateTime = KDateTime();
01447 }
01448 
01449 bool Date::isEmpty() const
01450 {
01451   return d_func()->dateTime.isNull() || !d_func()->dateTime.isValid();
01452 }
01453 
01454 KDateTime Date::dateTime() const
01455 {
01456   return d_func()->dateTime;
01457 }
01458 
01459 void Date::setDateTime( const KDateTime &dt )
01460 {
01461   Q_D(Date);
01462   d->dateTime = dt;
01463 }
01464 
01465 int Date::ageInDays() const
01466 {
01467   QDate today = QDate::currentDate();
01468   return dateTime().date().daysTo(today);
01469 }
01470 
01471 bool Date::parse( const char* &scursor, const char *const send, bool isCRLF )
01472 {
01473   Q_D(Date);
01474   return parseDateTime( scursor, send, d->dateTime, isCRLF );
01475 }
01476 
01477 //-----</Date>---------------------------------
01478 
01479 //-----<Newsgroups>----------------------------
01480 
01481 //@cond PRIVATE
01482 kmime_mk_trivial_ctor_with_name_and_dptr( Newsgroups, Generics::Structured, Newsgroups )
01483 kmime_mk_trivial_ctor_with_name( FollowUpTo, Newsgroups, Followup-To )
01484 //@endcond
01485 
01486 QByteArray Newsgroups::as7BitString( bool withHeaderType ) const
01487 {
01488   const Q_D(Newsgroups);
01489   if ( isEmpty() ) {
01490     return QByteArray();
01491   }
01492 
01493   QByteArray rv;
01494   if ( withHeaderType ) {
01495     rv += typeIntro();
01496   }
01497 
01498   for ( int i = 0; i < d->groups.count(); ++i ) {
01499     rv += d->groups[ i ];
01500     if ( i != d->groups.count() - 1 ) {
01501       rv += ',';
01502     }
01503   }
01504   return rv;
01505 }
01506 
01507 void Newsgroups::fromUnicodeString( const QString &s, const QByteArray &b )
01508 {
01509   Q_UNUSED( b );
01510   Q_D(Newsgroups);
01511   from7BitString( s.toUtf8() );
01512   d->encCS = cachedCharset( "UTF-8" );
01513 }
01514 
01515 QString Newsgroups::asUnicodeString() const
01516 {
01517   return QString::fromUtf8( as7BitString( false ) );
01518 }
01519 
01520 void Newsgroups::clear()
01521 {
01522   Q_D(Newsgroups);
01523   d->groups.clear();
01524 }
01525 
01526 bool Newsgroups::isEmpty() const
01527 {
01528   return d_func()->groups.isEmpty();
01529 }
01530 
01531 QList<QByteArray> Newsgroups::groups() const
01532 {
01533   return d_func()->groups;
01534 }
01535 
01536 void Newsgroups::setGroups( const QList<QByteArray> &groups )
01537 {
01538   Q_D(Newsgroups);
01539   d->groups = groups;
01540 }
01541 
01542 bool Newsgroups::isCrossposted() const
01543 {
01544   return d_func()->groups.count() >= 2;
01545 }
01546 
01547 bool Newsgroups::parse( const char* &scursor, const char *const send, bool isCRLF )
01548 {
01549   Q_D(Newsgroups);
01550   clear();
01551   forever {
01552     eatCFWS( scursor, send, isCRLF );
01553     if ( scursor != send && *scursor == ',' ) {
01554       ++scursor;
01555     }
01556     eatCFWS( scursor, send, isCRLF );
01557     if ( scursor == send ) {
01558       return true;
01559     }
01560     const char *start = scursor;
01561     while ( scursor != send && !isspace( *scursor ) && *scursor != ',' ) {
01562       ++scursor;
01563     }
01564     QByteArray group( start, scursor - start );
01565     d->groups.append( group );
01566   }
01567   return true;
01568 }
01569 
01570 //-----</Newsgroups>---------------------------
01571 
01572 //-----<Lines>---------------------------------
01573 
01574 //@cond PRIVATE
01575 kmime_mk_trivial_ctor_with_name_and_dptr( Lines, Generics::Structured, Lines )
01576 //@endcond
01577 
01578 QByteArray Lines::as7BitString( bool withHeaderType ) const
01579 {
01580   if ( isEmpty() ) {
01581     return QByteArray();
01582   }
01583 
01584   QByteArray num;
01585   num.setNum( d_func()->lines );
01586 
01587   if ( withHeaderType ) {
01588     return typeIntro() + num;
01589   }
01590   return num;
01591 }
01592 
01593 QString Lines::asUnicodeString() const
01594 {
01595   if ( isEmpty() ) {
01596     return QString();
01597   }
01598   return QString::number( d_func()->lines );
01599 }
01600 
01601 void Lines::clear()
01602 {
01603   Q_D(Lines);
01604   d->lines = -1;
01605 }
01606 
01607 bool Lines::isEmpty() const
01608 {
01609   return d_func()->lines == -1;
01610 }
01611 
01612 int Lines::numberOfLines() const
01613 {
01614   return d_func()->lines;
01615 }
01616 
01617 void Lines::setNumberOfLines( int lines )
01618 {
01619   Q_D(Lines);
01620   d->lines = lines;
01621 }
01622 
01623 bool Lines::parse( const char* &scursor, const char* const send, bool isCRLF )
01624 {
01625   Q_D(Lines);
01626   eatCFWS( scursor, send, isCRLF );
01627   if ( parseDigits( scursor, send, d->lines )  == 0 ) {
01628     clear();
01629     return false;
01630   }
01631   return true;
01632 }
01633 
01634 //-----</Lines>--------------------------------
01635 
01636 //-----<Content-Type>--------------------------
01637 
01638 //@cond PRIVATE
01639 kmime_mk_trivial_ctor_with_name_and_dptr( ContentType, Generics::Parametrized,
01640                                  Content-Type )
01641 //@endcond
01642 
01643 bool ContentType::isEmpty() const
01644 {
01645   return d_func()->mimeType.isEmpty();
01646 }
01647 
01648 void ContentType::clear()
01649 {
01650   Q_D(ContentType);
01651   d->category = CCsingle;
01652   d->mimeType.clear();
01653   d->mimeSubType.clear();
01654   Parametrized::clear();
01655 }
01656 
01657 QByteArray ContentType::as7BitString( bool withHeaderType ) const
01658 {
01659   if ( isEmpty() ) {
01660     return QByteArray();
01661   }
01662 
01663   QByteArray rv;
01664   if ( withHeaderType ) {
01665     rv += typeIntro();
01666   }
01667 
01668   rv += mimeType();
01669   if ( !Parametrized::isEmpty() ) {
01670     rv += "; " + Parametrized::as7BitString( false );
01671   }
01672 
01673   return rv;
01674 }
01675 
01676 QByteArray ContentType::mimeType() const
01677 {
01678   return d_func()->mimeType + '/' + d_func()->mimeSubType;
01679 }
01680 
01681 QByteArray ContentType::mediaType() const
01682 {
01683   return d_func()->mimeType;
01684 }
01685 
01686 QByteArray ContentType::subType() const
01687 {
01688   return d_func()->mimeSubType;
01689 }
01690 
01691 void ContentType::setMimeType( const QByteArray &mimeType )
01692 {
01693   Q_D(ContentType);
01694   int pos = mimeType.indexOf( '/' );
01695   if ( pos < 0 ) {
01696     d->mimeType = mimeType;
01697     d->mimeSubType.clear();
01698   } else {
01699     d->mimeType = mimeType.left( pos );
01700     d->mimeSubType = mimeType.mid( pos + 1 );
01701   }
01702   Parametrized::clear();
01703 
01704   if ( isMultipart() ) {
01705     d->category = CCcontainer;
01706   } else {
01707     d->category = CCsingle;
01708   }
01709 }
01710 
01711 bool ContentType::isMediatype( const char *mediatype ) const
01712 {
01713   return strncasecmp( mediaType().constData(), mediatype, strlen( mediatype ) ) == 0;
01714 }
01715 
01716 bool ContentType::isSubtype( const char *subtype ) const
01717 {
01718   return strncasecmp( subType().constData(), subtype, strlen( subtype ) ) == 0;
01719 }
01720 
01721 bool ContentType::isText() const
01722 {
01723   return strncasecmp( mediaType().constData(), "text", 4 ) == 0;
01724 }
01725 
01726 bool ContentType::isPlainText() const
01727 {
01728   return strcasecmp( mimeType().constData(), "text/plain" ) == 0;
01729 }
01730 
01731 bool ContentType::isHTMLText() const
01732 {
01733   return strcasecmp( mimeType().constData(), "text/html" ) == 0;
01734 }
01735 
01736 bool ContentType::isImage() const
01737 {
01738   return strncasecmp( mediaType().constData(), "image", 5 ) == 0;
01739 }
01740 
01741 bool ContentType::isMultipart() const
01742 {
01743   return strncasecmp( mediaType().constData(), "multipart", 9 ) == 0;
01744 }
01745 
01746 bool ContentType::isPartial() const
01747 {
01748   return strcasecmp( mimeType().constData(), "message/partial" ) == 0;
01749 }
01750 
01751 QByteArray ContentType::charset() const
01752 {
01753   QByteArray ret = parameter( "charset" ).toLatin1();
01754   if ( ret.isEmpty() || forceDefaultCharset() ) {
01755     //return the default-charset if necessary
01756     ret = defaultCharset();
01757   }
01758   return ret;
01759 }
01760 
01761 void ContentType::setCharset( const QByteArray &s )
01762 {
01763   setParameter( "charset", QString::fromLatin1( s ) );
01764 }
01765 
01766 QByteArray ContentType::boundary() const
01767 {
01768   return parameter( "boundary" ).toLatin1();
01769 }
01770 
01771 void ContentType::setBoundary( const QByteArray &s )
01772 {
01773   setParameter( "boundary", QString::fromLatin1( s ) );
01774 }
01775 
01776 QString ContentType::name() const
01777 {
01778   return parameter( "name" );
01779 }
01780 
01781 void ContentType::setName( const QString &s, const QByteArray &cs )
01782 {
01783   Q_D(ContentType);
01784   d->encCS = cs;
01785   setParameter( "name", s );
01786 }
01787 
01788 QByteArray ContentType::id() const
01789 {
01790   return parameter( "id" ).toLatin1();
01791 }
01792 
01793 void ContentType::setId( const QByteArray &s )
01794 {
01795   setParameter( "id", s );
01796 }
01797 
01798 int ContentType::partialNumber() const
01799 {
01800   QByteArray p = parameter( "number" ).toLatin1();
01801   if ( !p.isEmpty() ) {
01802     return p.toInt();
01803   } else {
01804     return -1;
01805   }
01806 }
01807 
01808 int ContentType::partialCount() const
01809 {
01810   QByteArray p = parameter( "total" ).toLatin1();
01811   if ( !p.isEmpty() ) {
01812     return p.toInt();
01813   } else {
01814     return -1;
01815   }
01816 }
01817 
01818 contentCategory ContentType::category() const
01819 {
01820   return d_func()->category;
01821 }
01822 
01823 void ContentType::setCategory( contentCategory c )
01824 {
01825   Q_D(ContentType);
01826   d->category = c;
01827 }
01828 
01829 void ContentType::setPartialParams( int total, int number )
01830 {
01831   setParameter( "number", QString::number( number ) );
01832   setParameter( "total", QString::number( total ) );
01833 }
01834 
01835 bool ContentType::parse( const char* &scursor, const char * const send,
01836                          bool isCRLF )
01837 {
01838   Q_D(ContentType);
01839   // content-type: type "/" subtype *(";" parameter)
01840 
01841   clear();
01842   eatCFWS( scursor, send, isCRLF );
01843   if ( scursor == send ) {
01844     return false; // empty header
01845   }
01846 
01847   // type
01848   QPair<const char*,int> maybeMimeType;
01849   if ( !parseToken( scursor, send, maybeMimeType, false /* no 8Bit */ ) ) {
01850     return false;
01851   }
01852   d->mimeType = QByteArray( maybeMimeType.first, maybeMimeType.second ).toLower();
01853 
01854   // subtype
01855   eatCFWS( scursor, send, isCRLF );
01856   if ( scursor == send || *scursor != '/' ) {
01857     return false;
01858   }
01859   scursor++;
01860   eatCFWS( scursor, send, isCRLF );
01861   if ( scursor == send ) {
01862     return false;
01863   }
01864 
01865   QPair<const char*,int> maybeSubType;
01866   if ( !parseToken( scursor, send, maybeSubType, false /* no 8bit */ ) ) {
01867     return false;
01868   }
01869   d->mimeSubType = QByteArray( maybeSubType.first, maybeSubType.second ).toLower();
01870 
01871   // parameter list
01872   eatCFWS( scursor, send, isCRLF );
01873   if ( scursor == send ) {
01874     goto success; // no parameters
01875   }
01876 
01877   if ( *scursor != ';' ) {
01878     return false;
01879   }
01880   scursor++;
01881 
01882   if ( !Parametrized::parse( scursor, send, isCRLF ) ) {
01883     return false;
01884   }
01885 
01886   // adjust category
01887 success:
01888   if ( isMultipart() ) {
01889     d->category = CCcontainer;
01890   } else {
01891     d->category = CCsingle;
01892   }
01893   return true;
01894 }
01895 
01896 //-----</Content-Type>-------------------------
01897 
01898 //-----<ContentTransferEncoding>----------------------------
01899 
01900 //@cond PRIVATE
01901 kmime_mk_trivial_ctor_with_name_and_dptr( ContentTransferEncoding,
01902                                  Generics::Token, Content-Transfer-Encoding )
01903 //@endcond
01904 
01905 typedef struct { const char *s; int e; } encTableType;
01906 
01907 static const encTableType encTable[] =
01908 {
01909   { "7Bit", CE7Bit },
01910   { "8Bit", CE8Bit },
01911   { "quoted-printable", CEquPr },
01912   { "base64", CEbase64 },
01913   { "x-uuencode", CEuuenc },
01914   { "binary", CEbinary },
01915   { 0, 0}
01916 };
01917 
01918 void ContentTransferEncoding::clear()
01919 {
01920   Q_D(ContentTransferEncoding);
01921   d->decoded = true;
01922   d->cte = CE7Bit;
01923   Token::clear();
01924 }
01925 
01926 contentEncoding ContentTransferEncoding::encoding() const
01927 {
01928   return d_func()->cte;
01929 }
01930 
01931 void ContentTransferEncoding::setEncoding( contentEncoding e )
01932 {
01933   Q_D(ContentTransferEncoding);
01934   d->cte = e;
01935 
01936   for ( int i = 0; encTable[i].s != 0; ++i ) {
01937     if ( d->cte == encTable[i].e ) {
01938       setToken( encTable[i].s );
01939       break;
01940     }
01941   }
01942 }
01943 
01944 bool ContentTransferEncoding::decoded() const
01945 {
01946   return d_func()->decoded;
01947 }
01948 
01949 void ContentTransferEncoding::setDecoded( bool decoded )
01950 {
01951   Q_D(ContentTransferEncoding);
01952   d->decoded = decoded;
01953 }
01954 
01955 bool ContentTransferEncoding::needToEncode() const
01956 {
01957   const Q_D(ContentTransferEncoding);
01958   return d->decoded && (d->cte == CEquPr || d->cte == CEbase64);
01959 }
01960 
01961 bool ContentTransferEncoding::parse( const char *& scursor,
01962                                      const char * const send, bool isCRLF )
01963 {
01964   Q_D(ContentTransferEncoding);
01965   clear();
01966   if ( !Token::parse( scursor, send, isCRLF ) ) {
01967     return false;
01968   }
01969 
01970   // TODO: error handling in case of an unknown encoding?
01971   for ( int i = 0; encTable[i].s != 0; ++i ) {
01972     if ( strcasecmp( token().constData(), encTable[i].s ) == 0 ) {
01973       d->cte = ( contentEncoding )encTable[i].e;
01974       break;
01975     }
01976   }
01977   d->decoded = ( d->cte == CE7Bit || d->cte == CE8Bit );
01978   return true;
01979 }
01980 
01981 //-----</ContentTransferEncoding>---------------------------
01982 
01983 //-----<ContentDisposition>--------------------------
01984 
01985 //@cond PRIVATE
01986 kmime_mk_trivial_ctor_with_name_and_dptr( ContentDisposition,
01987                                  Generics::Parametrized, Content-Disposition )
01988 //@endcond
01989 
01990 QByteArray ContentDisposition::as7BitString( bool withHeaderType ) const
01991 {
01992   if ( isEmpty() ) {
01993     return QByteArray();
01994   }
01995 
01996   QByteArray rv;
01997   if ( withHeaderType ) {
01998     rv += typeIntro();
01999   }
02000 
02001   if ( d_func()->disposition == CDattachment ) {
02002     rv += "attachment";
02003   } else if ( d_func()->disposition == CDinline ) {
02004     rv += "inline";
02005   } else {
02006     return QByteArray();
02007   }
02008 
02009   if ( !Parametrized::isEmpty() ) {
02010     rv += "; " + Parametrized::as7BitString( false );
02011   }
02012 
02013   return rv;
02014 }
02015 
02016 bool ContentDisposition::isEmpty() const
02017 {
02018   return d_func()->disposition == CDInvalid;
02019 }
02020 
02021 void ContentDisposition::clear()
02022 {
02023   Q_D(ContentDisposition);
02024   d->disposition = CDInvalid;
02025   Parametrized::clear();
02026 }
02027 
02028 contentDisposition ContentDisposition::disposition() const
02029 {
02030   return d_func()->disposition;
02031 }
02032 
02033 void ContentDisposition::setDisposition( contentDisposition disp )
02034 {
02035   Q_D(ContentDisposition);
02036   d->disposition = disp;
02037 }
02038 
02039 QString KMime::Headers::ContentDisposition::filename() const
02040 {
02041   return parameter( "filename" );
02042 }
02043 
02044 void ContentDisposition::setFilename( const QString &filename )
02045 {
02046   setParameter( "filename", filename );
02047 }
02048 
02049 bool ContentDisposition::parse( const char *& scursor, const char * const send,
02050                                 bool isCRLF )
02051 {
02052   Q_D(ContentDisposition);
02053   clear();
02054 
02055   // token
02056   QByteArray token;
02057   eatCFWS( scursor, send, isCRLF );
02058   if ( scursor == send ) {
02059     return false;
02060   }
02061 
02062   QPair<const char*,int> maybeToken;
02063   if ( !parseToken( scursor, send, maybeToken, false /* no 8Bit */ ) ) {
02064     return false;
02065   }
02066 
02067   token = QByteArray( maybeToken.first, maybeToken.second ).toLower();
02068   if ( token == "inline" ) {
02069     d->disposition = CDinline;
02070   } else if ( token == "attachment" ) {
02071     d->disposition = CDattachment;
02072   } else {
02073     return false;
02074   }
02075 
02076   // parameter list
02077   eatCFWS( scursor, send, isCRLF );
02078   if ( scursor == send ) {
02079     return true; // no parameters
02080   }
02081 
02082   if ( *scursor != ';' ) {
02083     return false;
02084   }
02085   scursor++;
02086 
02087   return Parametrized::parse( scursor, send, isCRLF );
02088 }
02089 
02090 //-----</ContentDisposition>-------------------------
02091 
02092 //@cond PRIVATE
02093 kmime_mk_trivial_ctor_with_name( Subject, Generics::Unstructured, Subject )
02094 //@endcond
02095 
02096 bool Subject::isReply() const
02097 {
02098   return asUnicodeString().indexOf( QLatin1String( "Re:" ), 0, Qt::CaseInsensitive ) == 0;
02099 }
02100 
02101 //@cond PRIVATE
02102 kmime_mk_trivial_ctor_with_name( ContentDescription,
02103                                  Generics::Unstructured, Content-Description )
02104 kmime_mk_trivial_ctor_with_name( From, Generics::MailboxList, From )
02105 kmime_mk_trivial_ctor_with_name( Sender, Generics::SingleMailbox, Sender )
02106 kmime_mk_trivial_ctor_with_name( To, Generics::AddressList, To )
02107 kmime_mk_trivial_ctor_with_name( Cc, Generics::AddressList, Cc )
02108 kmime_mk_trivial_ctor_with_name( Bcc, Generics::AddressList, Bcc )
02109 kmime_mk_trivial_ctor_with_name( ReplyTo, Generics::AddressList, Reply-To )
02110 kmime_mk_trivial_ctor_with_name( Keywords, Generics::PhraseList, Keywords )
02111 kmime_mk_trivial_ctor_with_name( MIMEVersion, Generics::DotAtom, MIME-Version )
02112 kmime_mk_trivial_ctor_with_name( ContentID, Generics::SingleIdent, Content-ID )
02113 kmime_mk_trivial_ctor_with_name( Supersedes, Generics::SingleIdent, Supersedes )
02114 kmime_mk_trivial_ctor_with_name( InReplyTo, Generics::Ident, In-Reply-To )
02115 kmime_mk_trivial_ctor_with_name( References, Generics::Ident, References )
02116 kmime_mk_trivial_ctor_with_name( Organization, Generics::Unstructured, Organization )
02117 kmime_mk_trivial_ctor_with_name( UserAgent, Generics::Unstructured, User-Agent )
02118 //@endcond
02119 
02120 } // namespace Headers
02121 
02122 } // namespace KMime

KMIME Library

Skip menu "KMIME Library"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.6
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal