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