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

KDE's Doxygen guidelines are available online.

KMIME Library

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

kdepimlibs-4.8.3 API Reference

Skip menu "kdepimlibs-4.8.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal