libkmime

kmime_headers.cpp

00001 /*
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 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012     You should have received a copy of the GNU General Public License
00013     along with this program; if not, write to the Free Software Foundation,
00014     Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
00015 */
00016 
00017 
00018 #include "kmime_headers.h"
00019 
00020 #include "kmime_util.h"
00021 #include "kmime_content.h"
00022 #include "kmime_codecs.h"
00023 #include "kmime_header_parsing.h"
00024 #include "kmime_warning.h"
00025 
00026 #include "kqcstringsplitter.h"
00027 
00028 #include <qtextcodec.h>
00029 #include <qstring.h>
00030 #include <qcstring.h>
00031 #include <qstringlist.h>
00032 #include <qvaluelist.h>
00033 
00034 #include <kglobal.h>
00035 #include <kcharsets.h>
00036 #include <krfcdate.h>
00037 
00038 #include <assert.h>
00039 
00040 
00041 using namespace KMime;
00042 using namespace KMime::Headers;
00043 using namespace KMime::Types;
00044 using namespace KMime::HeaderParsing;
00045 
00046 namespace KMime {
00047 namespace Headers {
00048 //-----<Base>----------------------------------
00049 
00050 QCString Base::rfc2047Charset()
00051 {
00052   if( (e_ncCS==0) || forceCS() )
00053     return defaultCS();
00054   else
00055     return QCString(e_ncCS);
00056 }
00057 
00058 
00059 void Base::setRFC2047Charset(const QCString &cs)
00060 {
00061   e_ncCS=cachedCharset(cs);
00062 }
00063 
00064 
00065 bool Base::forceCS()
00066 {
00067   return ( p_arent!=0 ? p_arent->forceDefaultCS() : false );
00068 }
00069 
00070 
00071 QCString Base::defaultCS()
00072 {
00073   return ( p_arent!=0 ? p_arent->defaultCharset() : Latin1 );
00074 }
00075 
00076 
00077 //-----</Base>---------------------------------
00078 
00079 namespace Generics {
00080 
00081 //-----<GUnstructured>-------------------------
00082 
00083 void GUnstructured::from7BitString( const QCString & str )
00084 {
00085   d_ecoded = decodeRFC2047String( str, &e_ncCS, defaultCS(), forceCS() );
00086 }
00087 
00088 QCString GUnstructured::as7BitString( bool withHeaderType )
00089 {
00090   QCString result;
00091   if ( withHeaderType )
00092     result = typeIntro();
00093   result += encodeRFC2047String( d_ecoded, e_ncCS ) ;
00094 
00095   return result;
00096 }
00097 
00098 void GUnstructured::fromUnicodeString( const QString & str,
00099                        const QCString & suggestedCharset )
00100 {
00101   d_ecoded = str;
00102   e_ncCS = cachedCharset( suggestedCharset );
00103 }
00104 
00105 QString GUnstructured::asUnicodeString()
00106 {
00107   return d_ecoded;
00108 }
00109 
00110 //-----</GUnstructured>-------------------------
00111 
00112 
00113 
00114 //-----<GStructured>-------------------------
00115 
00116 //-----</GStructured>-------------------------
00117 
00118 
00119 
00120 
00121 //-----<GAddress>-------------------------
00122 
00123 
00124 //-----</GAddress>-------------------------
00125 
00126 
00127 
00128 //-----<MailboxList>-------------------------
00129 
00130 bool MailboxList::parse( const char* & scursor, const char * const send,
00131              bool isCRLF ) {
00132   // examples:
00133   // from := "From:" mailbox-list CRLF
00134   // sender := "Sender:" mailbox CRLF
00135 
00136   // parse an address-list:
00137   QValueList<Address> maybeAddressList;
00138   if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) )
00139     return false;
00140 
00141   mMailboxList.clear();
00142 
00143   // extract the mailboxes and complain if there are groups:
00144   QValueList<Address>::Iterator it;
00145   for ( it = maybeAddressList.begin(); it != maybeAddressList.end() ; ++it ) {
00146     if ( !(*it).displayName.isEmpty() ) {
00147       KMIME_WARN << "mailbox groups in header disallowing them! Name: \""
00148          << (*it).displayName << "\"" << endl;
00149     }
00150     mMailboxList += (*it).mailboxList;
00151   }
00152   return true;
00153 }
00154 
00155 //-----</MailboxList>-------------------------
00156 
00157 
00158 
00159 //-----<SingleMailbox>-------------------------
00160 
00161 bool SingleMailbox::parse( const char* & scursor, const char * const send,
00162                bool isCRLF ) {
00163   if ( !MailboxList::parse( scursor, send, isCRLF ) ) return false;
00164 
00165   if ( mMailboxList.count() > 1 ) {
00166     KMIME_WARN << "multiple mailboxes in header allowing only a single one!"
00167            << endl;
00168   }
00169   return true;
00170 }
00171 
00172 //-----</SingleMailbox>-------------------------
00173 
00174 
00175 
00176 //-----<AddressList>-------------------------
00177 
00178 bool AddressList::parse( const char* & scursor, const char * const send,
00179              bool isCRLF ) {
00180 
00181   QValueList<Address> maybeAddressList;
00182   if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) )
00183     return false;
00184 
00185   mAddressList = maybeAddressList;
00186   return true;
00187 }
00188 
00189 //-----</AddressList>-------------------------
00190 
00191 
00192 
00193 //-----<GToken>-------------------------
00194 
00195 bool GToken::parse( const char* & scursor, const char * const send,
00196             bool isCRLF ) {
00197 
00198   eatCFWS( scursor, send, isCRLF );
00199   // must not be empty:
00200   if ( scursor == send ) return false;
00201 
00202   QPair<const char*,int> maybeToken;
00203   if ( !parseToken( scursor, send, maybeToken, false /* no 8bit chars */ ) )
00204     return false;
00205   mToken = QCString( maybeToken.first, maybeToken.second );
00206 
00207   // complain if trailing garbage is found:
00208   eatCFWS( scursor, send, isCRLF );
00209   if ( scursor != send ) {
00210     KMIME_WARN << "trailing garbage after token in header allowing "
00211       "only a single token!" << endl;
00212   }
00213   return true;
00214 }
00215 
00216 //-----</GToken>-------------------------
00217 
00218 
00219 
00220 //-----<GPhraseList>-------------------------
00221 
00222 bool GPhraseList::parse( const char* & scursor, const char * const send,
00223              bool isCRLF ) {
00224 
00225   mPhraseList.clear();
00226 
00227   while ( scursor != send ) {
00228     eatCFWS( scursor, send, isCRLF );
00229     // empty entry ending the list: OK.
00230     if ( scursor == send ) return true;
00231     // empty entry: ignore.
00232     if ( *scursor != ',' ) { scursor++; continue; }
00233 
00234     QString maybePhrase;
00235     if ( !parsePhrase( scursor, send, maybePhrase, isCRLF ) )
00236       return false;
00237     mPhraseList.append( maybePhrase );
00238 
00239     eatCFWS( scursor, send, isCRLF );
00240     // non-empty entry ending the list: OK.
00241     if ( scursor == send ) return true;
00242     // comma separating the phrases: eat.
00243     if ( *scursor != ',' ) scursor++;
00244   }
00245   return true;
00246 }
00247 
00248 //-----</GPhraseList>-------------------------
00249 
00250 
00251 
00252 //-----<GDotAtom>-------------------------
00253 
00254 bool GDotAtom::parse( const char* & scursor, const char * const send,
00255               bool isCRLF ) {
00256 
00257   QString maybeDotAtom;
00258   if ( !parseDotAtom( scursor, send, maybeDotAtom, isCRLF ) )
00259     return false;
00260 
00261   mDotAtom = maybeDotAtom;
00262 
00263   eatCFWS( scursor, send, isCRLF );
00264   if ( scursor != send ) {
00265     KMIME_WARN << "trailing garbage after dot-atom in header allowing "
00266       "only a single dot-atom!" << endl;
00267   }
00268   return true;
00269 }
00270 
00271 //-----</GDotAtom>-------------------------
00272 
00273 
00274 
00275 //-----<GParametrized>-------------------------
00276 
00277 //-----</GParametrized>-------------------------
00278 
00279 
00280 
00281 
00282 //-----</GContentType>-------------------------
00283 
00284 bool GContentType::parse( const char* & scursor, const char * const send,
00285               bool isCRLF ) {
00286 
00287   // content-type: type "/" subtype *(";" parameter)
00288 
00289   mMimeType = 0;
00290   mMimeSubType = 0;
00291   mParameterHash.clear();
00292 
00293   eatCFWS( scursor, send, isCRLF );
00294   if ( scursor == send ) {
00295     // empty header
00296     return false;
00297   }
00298 
00299   //
00300   // type
00301   //
00302 
00303   QPair<const char*,int> maybeMimeType;
00304   if ( !parseToken( scursor, send, maybeMimeType, false /* no 8Bit */ ) )
00305     return false;
00306 
00307   mMimeType = QCString( maybeMimeType.first, maybeMimeType.second ).lower();
00308 
00309   //
00310   // subtype
00311   //
00312 
00313   eatCFWS( scursor, send, isCRLF );
00314   if ( scursor == send || *scursor != '/' ) return false;
00315   scursor++;
00316   eatCFWS( scursor, send, isCRLF );
00317   if ( scursor == send ) return false;
00318 
00319   QPair<const char*,int> maybeSubType;
00320   if ( !parseToken( scursor, send, maybeSubType, false /* no 8bit */ ) )
00321     return false;
00322 
00323   mMimeSubType = QCString( maybeSubType.first, maybeSubType.second ).lower();
00324 
00325   //
00326   // parameter list
00327   //
00328 
00329   eatCFWS( scursor, send, isCRLF );
00330   if ( scursor == send ) return true; // no parameters
00331 
00332   if ( *scursor != ';' ) return false;
00333   scursor++;
00334 
00335   if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) )
00336     return false;
00337 
00338   return true;
00339 }
00340 
00341 //-----</GContentType>-------------------------
00342 
00343 
00344 
00345 //-----<GTokenWithParameterList>-------------------------
00346 
00347 bool GCISTokenWithParameterList::parse( const char* & scursor,
00348                     const char * const send, bool isCRLF ) {
00349 
00350   mToken = 0;
00351   mParameterHash.clear();
00352 
00353   //
00354   // token
00355   //
00356 
00357   eatCFWS( scursor, send, isCRLF );
00358   if ( scursor == send ) return false;
00359 
00360   QPair<const char*,int> maybeToken;
00361   if ( !parseToken( scursor, send, maybeToken, false /* no 8Bit */ ) )
00362     return false;
00363 
00364   mToken = QCString( maybeToken.first, maybeToken.second ).lower();
00365 
00366   //
00367   // parameter list
00368   //
00369 
00370   eatCFWS( scursor, send, isCRLF );
00371   if ( scursor == send ) return true; // no parameters
00372 
00373   if ( *scursor != ';' ) return false;
00374   scursor++;
00375 
00376   if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) )
00377     return false;
00378 
00379   return true;
00380 }
00381 
00382 //-----</GTokenWithParameterList>-------------------------
00383 
00384 
00385 
00386 //-----<GIdent>-------------------------
00387 
00388 bool GIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) {
00389 
00390   // msg-id   := "<" id-left "@" id-right ">"
00391   // id-left  := dot-atom-text / no-fold-quote / local-part
00392   // id-right := dot-atom-text / no-fold-literal / domain
00393   //
00394   // equivalent to:
00395   // msg-id   := angle-addr
00396 
00397   mMsgIdList.clear();
00398 
00399   while ( scursor != send ) {
00400     eatCFWS( scursor, send, isCRLF );
00401     // empty entry ending the list: OK.
00402     if ( scursor == send ) return true;
00403     // empty entry: ignore.
00404     if ( *scursor == ',' ) { scursor++; continue; }
00405 
00406     AddrSpec maybeMsgId;
00407     if ( !parseAngleAddr( scursor, send, maybeMsgId, isCRLF ) )
00408       return false;
00409     mMsgIdList.append( maybeMsgId );
00410 
00411     eatCFWS( scursor, send, isCRLF );
00412     // header end ending the list: OK.
00413     if ( scursor == send ) return true;
00414     // regular item separator: eat it.
00415     if ( *scursor == ',' ) scursor++;
00416   }
00417   return true;
00418 }
00419 
00420 //-----</GIdent>-------------------------
00421 
00422 
00423 
00424 //-----<GSingleIdent>-------------------------
00425 
00426 bool GSingleIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) {
00427 
00428   if ( !GIdent::parse( scursor, send, isCRLF ) ) return false;
00429 
00430   if ( mMsgIdList.count() > 1 ) {
00431     KMIME_WARN << "more than one msg-id in header "
00432       "allowing only a single one!" << endl;
00433   }
00434   return true;
00435 }
00436 
00437 //-----</GSingleIdent>-------------------------
00438 
00439 
00440 
00441 
00442 } // namespace Generics
00443 
00444 
00445 //-----<ReturnPath>-------------------------
00446 
00447 bool ReturnPath::parse( const char* & scursor, const char * const send, bool isCRLF ) {
00448 
00449   eatCFWS( scursor, send, isCRLF );
00450   if ( scursor == send ) return false;
00451 
00452   const char * oldscursor = scursor;
00453 
00454   Mailbox maybeMailbox;
00455   if ( !parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) {
00456     // mailbox parsing failed, but check for empty brackets:
00457     scursor = oldscursor;
00458     if ( *scursor != '<' ) return false;
00459     scursor++;
00460     eatCFWS( scursor, send, isCRLF );
00461     if ( scursor == send || *scursor != '>' ) return false;
00462     scursor++;
00463 
00464     // prepare a Null mailbox:
00465     AddrSpec emptyAddrSpec;
00466     maybeMailbox.displayName = QString::null;
00467     maybeMailbox.addrSpec = emptyAddrSpec;
00468   } else
00469     // check that there was no display-name:
00470     if ( !maybeMailbox.displayName.isEmpty() ) {
00471     KMIME_WARN << "display-name \"" << maybeMailbox.displayName
00472            << "\" in Return-Path!" << endl;
00473   }
00474 
00475   // see if that was all:
00476   eatCFWS( scursor, send, isCRLF );
00477   // and warn if it wasn't:
00478   if ( scursor != send ) {
00479     KMIME_WARN << "trailing garbage after angle-addr in Return-Path!" << endl;
00480   }
00481   return true;
00482 }
00483 
00484 //-----</ReturnPath>-------------------------
00485 
00486 
00487 
00488 
00489 //-----<Generic>-------------------------------
00490 
00491 void Generic::setType(const char *type)
00492 {
00493   if(t_ype)
00494     delete[] t_ype;
00495   if(type) {
00496     t_ype=new char[strlen(type)+1];
00497     strcpy(t_ype, type);
00498   }
00499   else
00500     t_ype=0;
00501 }
00502 
00503 //-----<Generic>-------------------------------
00504 
00505 
00506 #if !defined(KMIME_NEW_STYLE_CLASSTREE)
00507 //-----<MessageID>-----------------------------
00508 
00509 void MessageID::from7BitString(const QCString &s)
00510 {
00511   m_id=s;
00512 }
00513 
00514 
00515 QCString MessageID::as7BitString(bool incType)
00516 {
00517   if(incType)
00518     return ( typeIntro()+m_id );
00519   else
00520     return m_id;
00521 }
00522 
00523 
00524 void MessageID::fromUnicodeString(const QString &s, const QCString&)
00525 {
00526   m_id=s.latin1(); //Message-Ids can only contain us-ascii chars
00527 }
00528 
00529 
00530 QString MessageID::asUnicodeString()
00531 {
00532   return QString::fromLatin1(m_id);
00533 }
00534 
00535 
00536 void MessageID::generate(const QCString &fqdn)
00537 {
00538   m_id="<"+uniqueString()+"@"+fqdn+">";
00539 }
00540 
00541 //-----</MessageID>----------------------------
00542 #endif
00543 
00544 
00545 //-----<Control>-------------------------------
00546 
00547 void Control::from7BitString(const QCString &s)
00548 {
00549   c_trlMsg=s;
00550 }
00551 
00552 
00553 QCString Control::as7BitString(bool incType)
00554 {
00555   if(incType)
00556     return ( typeIntro()+c_trlMsg );
00557   else
00558     return c_trlMsg;
00559 }
00560 
00561 
00562 void Control::fromUnicodeString(const QString &s, const QCString&)
00563 {
00564   c_trlMsg=s.latin1();
00565 }
00566 
00567 
00568 QString Control::asUnicodeString()
00569 {
00570   return QString::fromLatin1(c_trlMsg);
00571 }
00572 
00573 //-----</Control>------------------------------
00574 
00575 
00576 
00577 #if !defined(KMIME_NEW_STYLE_CLASSTREE)
00578 //-----<AddressField>--------------------------
00579 void AddressField::from7BitString(const QCString &s)
00580 {
00581   int pos1=0, pos2=0, type=0;
00582   QCString n;
00583 
00584   //so what do we have here ?
00585   if(s.find( QRegExp("*@*(*)", false, true) )!=-1) type=2;       // From: foo@bar.com (John Doe)
00586   else if(s.find( QRegExp("*<*@*>", false, true) )!=-1) type=1;  // From: John Doe <foo@bar.com>
00587   else if(s.find( QRegExp("*@*", false, true) )!=-1) type=0;     // From: foo@bar.com
00588   else { //broken From header => just decode it
00589     n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS());
00590     return;
00591   }
00592 
00593   switch(type) {
00594 
00595     case 0:
00596       e_mail=s.copy();
00597     break;
00598 
00599     case 1:
00600       pos1=0;
00601       pos2=s.find('<');
00602       if(pos2!=-1) {
00603         n=s.mid(pos1, pos2-pos1).stripWhiteSpace();
00604         pos1=pos2+1;
00605         pos2=s.find('>', pos1);
00606         if(pos2!=-1)
00607           e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace();
00608       }
00609       else return;
00610     break;
00611 
00612     case 2:
00613       pos1=0;
00614       pos2=s.find('(');
00615       if(pos2!=-1) {
00616         e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace();
00617         pos1=pos2+1;
00618         pos2=s.find(')', pos1);
00619         if(pos2!=-1)
00620           n=s.mid(pos1, pos2-pos1).stripWhiteSpace();
00621       }
00622     break;
00623 
00624     default: break;
00625   }
00626 
00627   if(!n.isEmpty()) {
00628     removeQuots(n);
00629     n_ame=decodeRFC2047String(n, &e_ncCS, defaultCS(), forceCS());
00630   }
00631 }
00632 
00633 
00634 QCString AddressField::as7BitString(bool incType)
00635 {
00636   QCString ret;
00637 
00638   if(incType && type()[0]!='\0')
00639     ret=typeIntro();
00640 
00641   if(n_ame.isEmpty())
00642     ret+=e_mail;
00643   else {
00644     if (isUsAscii(n_ame)) {
00645       QCString tmp(n_ame.latin1());
00646       addQuotes(tmp, false);
00647       ret+=tmp;
00648     } else {
00649       ret+=encodeRFC2047String(n_ame, e_ncCS, true);
00650     }
00651     if (!e_mail.isEmpty())
00652       ret += " <"+e_mail+">";
00653   }
00654 
00655   return ret;
00656 }
00657 
00658 
00659 void AddressField::fromUnicodeString(const QString &s, const QCString &cs)
00660 {
00661   int pos1=0, pos2=0, type=0;
00662   QCString n;
00663 
00664   e_ncCS=cachedCharset(cs);
00665 
00666   //so what do we have here ?
00667   if(s.find( QRegExp("*@*(*)", false, true) )!=-1) type=2;       // From: foo@bar.com (John Doe)
00668   else if(s.find( QRegExp("*<*@*>", false, true) )!=-1) type=1;  // From: John Doe <foo@bar.com>
00669   else if(s.find( QRegExp("*@*", false, true) )!=-1) type=0;     // From: foo@bar.com
00670   else { //broken From header => just copy it
00671     n_ame=s;
00672     return;
00673   }
00674 
00675   switch(type) {
00676 
00677     case 0:
00678       e_mail=s.latin1();
00679     break;
00680 
00681     case 1:
00682       pos1=0;
00683       pos2=s.find('<');
00684       if(pos2!=-1) {
00685         n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace();
00686         pos1=pos2+1;
00687         pos2=s.find('>', pos1);
00688         if(pos2!=-1)
00689           e_mail=s.mid(pos1, pos2-pos1).latin1();
00690       }
00691       else return;
00692     break;
00693 
00694     case 2:
00695       pos1=0;
00696       pos2=s.find('(');
00697       if(pos2!=-1) {
00698         e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace().latin1();
00699         pos1=pos2+1;
00700         pos2=s.find(')', pos1);
00701         if(pos2!=-1)
00702           n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace();
00703       }
00704     break;
00705 
00706     default: break;
00707   }
00708 
00709   if(!n_ame.isEmpty())
00710     removeQuots(n_ame);
00711 }
00712 
00713 
00714 QString AddressField::asUnicodeString()
00715 {
00716   if(n_ame.isEmpty())
00717     return QString(e_mail);
00718   else {
00719     QString s = n_ame;
00720     if (!e_mail.isEmpty())
00721       s += " <"+e_mail+">";
00722     return s;
00723   }
00724 }
00725 
00726 
00727 QCString AddressField::nameAs7Bit()
00728 {
00729   return encodeRFC2047String(n_ame, e_ncCS);
00730 }
00731 
00732 
00733 void AddressField::setNameFrom7Bit(const QCString &s)
00734 {
00735   n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS());
00736 }
00737 
00738 //-----</AddressField>-------------------------
00739 #endif
00740 
00741 
00742 //-----<MailCopiesTo>--------------------------
00743 
00744 bool MailCopiesTo::isValid()
00745 {
00746   if (hasEmail())
00747     return true;
00748 
00749   if ((n_ame == "nobody") ||
00750       (n_ame == "never") ||
00751       (n_ame == "poster") ||
00752       (n_ame == "always"))
00753     return true;
00754   else
00755     return false;
00756 }
00757 
00758 
00759 bool MailCopiesTo::alwaysCopy()
00760 {
00761   return (hasEmail() || (n_ame == "poster") || (n_ame == "always"));
00762 }
00763 
00764 
00765 bool MailCopiesTo::neverCopy()
00766 {
00767   return ((n_ame == "nobody") || (n_ame == "never"));
00768 }
00769 
00770 //-----</MailCopiesTo>-------------------------
00771 
00772 
00773 
00774 
00775 //-----<Date>----------------------------------
00776 
00777 void Date::from7BitString(const QCString &s)
00778 {
00779   t_ime=KRFCDate::parseDate(s);
00780 }
00781 
00782 
00783 QCString Date::as7BitString(bool incType)
00784 {
00785   if(incType)
00786     return ( typeIntro()+KRFCDate::rfc2822DateString(t_ime) );
00787   else
00788     return QCString(KRFCDate::rfc2822DateString(t_ime));
00789 }
00790 
00791 
00792 void Date::fromUnicodeString(const QString &s, const QCString&)
00793 {
00794   from7BitString( QCString(s.latin1()) );
00795 }
00796 
00797 
00798 QString Date::asUnicodeString()
00799 {
00800   return QString::fromLatin1(as7BitString(false));
00801 }
00802 
00803 
00804 QDateTime Date::qdt()
00805 {
00806   QDateTime dt;
00807   dt.setTime_t(t_ime);
00808   return dt;
00809 }
00810 
00811 
00812 int Date::ageInDays()
00813 {
00814   QDate today=QDate::currentDate();
00815   return ( qdt().date().daysTo(today) );
00816 }
00817 
00818 //-----</Date>---------------------------------
00819 
00820 
00821 
00822 #if !defined(KMIME_NEW_STYLE_CLASSTREE)
00823 //-----<To>------------------------------------
00824 
00825 void To::from7BitString(const QCString &s)
00826 {
00827   if(a_ddrList)
00828     a_ddrList->clear();
00829   else {
00830     a_ddrList=new QPtrList<AddressField>;
00831     a_ddrList->setAutoDelete(true);
00832   }
00833 
00834   KQCStringSplitter split;
00835   split.init(s, ",");
00836   bool splitOk=split.first();
00837   if(!splitOk)
00838     a_ddrList->append( new AddressField(p_arent, s ));
00839   else {
00840     do {
00841       a_ddrList->append( new AddressField(p_arent, split.string()) );
00842     } while(split.next());
00843   }
00844 
00845   e_ncCS=cachedCharset(a_ddrList->first()->rfc2047Charset());
00846 }
00847 
00848 
00849 QCString To::as7BitString(bool incType)
00850 {
00851   QCString ret;
00852 
00853   if(incType)
00854     ret+=typeIntro();
00855 
00856   if (a_ddrList) {
00857     AddressField *it=a_ddrList->first();
00858     if (it)
00859       ret+=it->as7BitString(false);
00860     for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() )
00861       ret+=","+it->as7BitString(false);
00862   }
00863 
00864   return ret;
00865 }
00866 
00867 
00868 void To::fromUnicodeString(const QString &s, const QCString &cs)
00869 {
00870   if(a_ddrList)
00871     a_ddrList->clear();
00872   else  {
00873     a_ddrList=new QPtrList<AddressField>;
00874     a_ddrList->setAutoDelete(true);
00875   }
00876 
00877   QStringList l=QStringList::split(",", s);
00878 
00879   QStringList::Iterator it=l.begin();
00880   for(; it!=l.end(); ++it)
00881     a_ddrList->append(new AddressField( p_arent, (*it), cs ));
00882 
00883   e_ncCS=cachedCharset(cs);
00884 }
00885 
00886 
00887 QString To::asUnicodeString()
00888 {
00889   if(!a_ddrList)
00890     return QString::null;
00891 
00892   QString ret;
00893   AddressField *it=a_ddrList->first();
00894 
00895   if (it)
00896     ret+=it->asUnicodeString();
00897   for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() )
00898     ret+=","+it->asUnicodeString();
00899   return ret;
00900 }
00901 
00902 
00903 void To::addAddress(const AddressField &a)
00904 {
00905   if(!a_ddrList) {
00906     a_ddrList=new QPtrList<AddressField>;
00907     a_ddrList->setAutoDelete(true);
00908   }
00909 
00910   AddressField *add=new AddressField(a);
00911   add->setParent(p_arent);
00912   a_ddrList->append(add);
00913 }
00914 
00915 
00916 void To::emails(QStrList *l)
00917 {
00918   l->clear();
00919 
00920   for (AddressField *it=a_ddrList->first(); it != 0; it=a_ddrList->next() )
00921     if( it->hasEmail() )
00922       l->append( it->email() );
00923 }
00924 
00925 void To::names(QStringList *l)
00926 {
00927     l->clear();
00928 
00929     for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() )
00930         if( it->hasName() )
00931             l->append( it->name() );
00932 }
00933 
00934 void To::displayNames(QStringList *l)
00935 {
00936     l->clear();
00937 
00938     for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() )
00939             l->append( it->asUnicodeString() );
00940 }
00941 
00942 //-----</To>-----------------------------------
00943 #endif
00944 
00945 
00946 //-----<Newsgroups>----------------------------
00947 
00948 void Newsgroups::from7BitString(const QCString &s)
00949 {
00950   g_roups=s;
00951   e_ncCS=cachedCharset("UTF-8");
00952 }
00953 
00954 
00955 QCString Newsgroups::as7BitString(bool incType)
00956 {
00957   if(incType)
00958     return (typeIntro()+g_roups);
00959   else
00960     return g_roups;
00961 }
00962 
00963 
00964 void Newsgroups::fromUnicodeString(const QString &s, const QCString&)
00965 {
00966   g_roups=s.utf8();
00967   e_ncCS=cachedCharset("UTF-8");
00968 }
00969 
00970 
00971 QString Newsgroups::asUnicodeString()
00972 {
00973   return QString::fromUtf8(g_roups);
00974 }
00975 
00976 
00977 QCString Newsgroups::firstGroup()
00978 {
00979   int pos=0;
00980   if(!g_roups.isEmpty()) {
00981     pos=g_roups.find(',');
00982     if(pos==-1)
00983       return g_roups;
00984     else
00985       return g_roups.left(pos);
00986   }
00987   else
00988     return QCString();
00989 }
00990 
00991 
00992 QStringList Newsgroups::getGroups()
00993 {
00994   QStringList temp = QStringList::split(',', g_roups);
00995   QStringList ret;
00996   QString s;
00997 
00998   for (QStringList::Iterator it = temp.begin(); it != temp.end(); ++it ) {
00999     s = (*it).simplifyWhiteSpace();
01000     ret.append(s);
01001   }
01002 
01003   return ret;
01004 }
01005 
01006 //-----</Newsgroups>---------------------------
01007 
01008 
01009 
01010 //-----<Lines>---------------------------------
01011 
01012 void Lines::from7BitString(const QCString &s)
01013 {
01014   l_ines=s.toInt();
01015   e_ncCS=cachedCharset(Latin1);
01016 }
01017 
01018 
01019 QCString Lines::as7BitString(bool incType)
01020 {
01021   QCString num;
01022   num.setNum(l_ines);
01023 
01024   if(incType)
01025     return ( typeIntro()+num );
01026   else
01027     return num;
01028 }
01029 
01030 
01031 void Lines::fromUnicodeString(const QString &s, const QCString&)
01032 {
01033   l_ines=s.toInt();
01034   e_ncCS=cachedCharset(Latin1);
01035 }
01036 
01037 
01038 QString Lines::asUnicodeString()
01039 {
01040   QString num;
01041   num.setNum(l_ines);
01042 
01043   return num;
01044 }
01045 
01046 //-----</Lines>--------------------------------
01047 
01048 
01049 
01050 #if !defined(KMIME_NEW_STYLE_CLASSTREE)
01051 //-----<References>----------------------------
01052 
01053 void References::from7BitString(const QCString &s)
01054 {
01055   r_ef=s;
01056   e_ncCS=cachedCharset(Latin1);
01057 }
01058 
01059 
01060 QCString References::as7BitString(bool incType)
01061 {
01062   if(incType)
01063     return ( typeIntro()+r_ef );
01064   else
01065     return r_ef;
01066 }
01067 
01068 
01069 void References::fromUnicodeString(const QString &s, const QCString&)
01070 {
01071   r_ef=s.latin1();
01072   e_ncCS=cachedCharset(Latin1);
01073 }
01074 
01075 
01076 QString References::asUnicodeString()
01077 {
01078   return QString::fromLatin1(r_ef);
01079 }
01080 
01081 
01082 int References::count()
01083 {
01084   int cnt1=0, cnt2=0;
01085   unsigned int r_efLen=r_ef.length();
01086   char *dataPtr=r_ef.data();
01087   for(unsigned int i=0; i<r_efLen; i++) {
01088     if(dataPtr[i]=='<') cnt1++;
01089     else if(dataPtr[i]=='>') cnt2++;
01090   }
01091 
01092   if(cnt1<cnt2) return cnt1;
01093   else return cnt2;
01094 }
01095 
01096 
01097 QCString References::first()
01098 {
01099   p_os=-1;
01100   return next();
01101 }
01102 
01103 
01104 QCString References::next()
01105 {
01106   int pos1=0, pos2=0;
01107   QCString ret;
01108 
01109   if(p_os!=0) {
01110     pos2=r_ef.findRev('>', p_os);
01111     p_os=0;
01112     if(pos2!=-1) {
01113       pos1=r_ef.findRev('<', pos2);
01114       if(pos1!=-1) {
01115         ret=r_ef.mid(pos1, pos2-pos1+1);
01116         p_os=pos1;
01117       }
01118     }
01119   }
01120   return ret;
01121 }
01122 
01123 
01124 QCString References::at(unsigned int i)
01125 {
01126   QCString ret;
01127   int pos1=0, pos2=0;
01128   unsigned int cnt=0;
01129 
01130   while(pos1!=-1 && cnt < i+1) {
01131     pos2=pos1-1;
01132     pos1=r_ef.findRev('<', pos2);
01133     cnt++;
01134   }
01135 
01136   if(pos1!=-1) {
01137     pos2=r_ef.find('>', pos1);
01138     if(pos2!=-1)
01139       ret=r_ef.mid(pos1, pos2-pos1+1);
01140   }
01141 
01142  return ret;
01143 }
01144 
01145 
01146 void References::append(const QCString &s)
01147 {
01148   QString temp=r_ef.data();
01149   temp += " ";
01150   temp += s.data();
01151   QStringList lst=QStringList::split(' ',temp);
01152   QRegExp exp("^<.+@.+>$");
01153 
01154   // remove bogus references
01155   QStringList::Iterator it = lst.begin();
01156   while (it != lst.end()) {
01157     if (-1==(*it).find(exp))
01158       it = lst.remove(it);
01159     else
01160       it++;
01161   }
01162 
01163   if (lst.isEmpty()) {
01164     r_ef = s.copy();    // shouldn't happen...
01165     return;
01166   } else
01167     r_ef = "";
01168 
01169   temp = lst.first();    // include the first id
01170   r_ef = temp.latin1();
01171   lst.remove(temp);         // avoids duplicates
01172   int insPos = r_ef.length();
01173 
01174   for (int i=1;i<=3;i++) {    // include the last three ids
01175     if (!lst.isEmpty()) {
01176       temp = lst.last();
01177       r_ef.insert(insPos,(QString(" %1").arg(temp)).latin1());
01178       lst.remove(temp);
01179     } else
01180       break;
01181   }
01182 
01183   while (!lst.isEmpty()) {   // now insert the rest, up to 1000 characters
01184     temp = lst.last();
01185     if ((15+r_ef.length()+temp.length())<1000) {
01186       r_ef.insert(insPos,(QString(" %1").arg(temp)).latin1());
01187       lst.remove(temp);
01188     } else
01189       return;
01190   }
01191 }
01192 
01193 //-----</References>---------------------------
01194 #endif
01195 
01196 
01197 //-----<UserAgent>-----------------------------
01198 
01199 void UserAgent::from7BitString(const QCString &s)
01200 {
01201   u_agent=s;
01202   e_ncCS=cachedCharset(Latin1);
01203 }
01204 
01205 
01206 QCString UserAgent::as7BitString(bool incType)
01207 {
01208   if(incType)
01209     return ( typeIntro()+u_agent );
01210   else
01211     return u_agent;
01212 }
01213 
01214 
01215 void UserAgent::fromUnicodeString(const QString &s, const QCString&)
01216 {
01217   u_agent=s.latin1();
01218   e_ncCS=cachedCharset(Latin1);
01219 }
01220 
01221 
01222 QString UserAgent::asUnicodeString()
01223 {
01224   return QString::fromLatin1(u_agent);
01225 }
01226 
01227 //-----</UserAgent>----------------------------
01228 
01229 
01230 
01231 #if !defined(KMIME_NEW_STYLE_CLASSTREE)
01232 //-----<Content-Type>--------------------------
01233 
01234 void ContentType::from7BitString(const QCString &s)
01235 {
01236   int pos=s.find(';');
01237 
01238   if(pos==-1)
01239     m_imeType=s.simplifyWhiteSpace();
01240   else {
01241     m_imeType=s.left(pos).simplifyWhiteSpace();
01242     p_arams=s.mid(pos, s.length()-pos).simplifyWhiteSpace();
01243   }
01244 
01245   if(isMultipart())
01246     c_ategory=CCcontainer;
01247   else
01248     c_ategory=CCsingle;
01249 
01250   e_ncCS=cachedCharset(Latin1);
01251 }
01252 
01253 
01254 QCString ContentType::as7BitString(bool incType)
01255 {
01256   if(incType)
01257     return (typeIntro()+m_imeType+p_arams);
01258   else
01259     return (m_imeType+p_arams);
01260 }
01261 
01262 
01263 void ContentType::fromUnicodeString(const QString &s, const QCString&)
01264 {
01265   from7BitString( QCString(s.latin1()) );
01266 }
01267 
01268 
01269 QString ContentType::asUnicodeString()
01270 {
01271   return QString::fromLatin1(as7BitString(false));
01272 }
01273 
01274 
01275 QCString ContentType::mediaType()
01276 {
01277   int pos=m_imeType.find('/');
01278   if(pos==-1)
01279     return m_imeType;
01280   else
01281     return m_imeType.left(pos);
01282 }
01283 
01284 
01285 QCString ContentType::subType()
01286 {
01287   int pos=m_imeType.find('/');
01288   if(pos==-1)
01289     return QCString();
01290   else
01291     return m_imeType.mid(pos, m_imeType.length()-pos);
01292 }
01293 
01294 
01295 void ContentType::setMimeType(const QCString &s)
01296 {
01297   p_arams.resize(0);
01298   m_imeType=s;
01299 
01300   if(isMultipart())
01301     c_ategory=CCcontainer;
01302   else
01303     c_ategory=CCsingle;
01304 }
01305 
01306 
01307 bool ContentType::isMediatype(const char *s)
01308 {
01309   return ( strncasecmp(m_imeType.data(), s, strlen(s)) );
01310 }
01311 
01312 
01313 bool ContentType::isSubtype(const char *s)
01314 {
01315   char *c=strchr(m_imeType.data(), '/');
01316 
01317   if( (c==0) || (*(c+1)=='\0') )
01318     return false;
01319   else
01320     return ( strcasecmp(c+1, s)==0 );
01321 }
01322 
01323 
01324 bool ContentType::isText()
01325 {
01326   return (strncasecmp(m_imeType.data(), "text", 4)==0);
01327 }
01328 
01329 
01330 bool ContentType::isPlainText()
01331 {
01332   return (strcasecmp(m_imeType.data(), "text/plain")==0);
01333 }
01334 
01335 
01336 bool ContentType::isHTMLText()
01337 {
01338   return (strcasecmp(m_imeType.data(), "text/html")==0);
01339 }
01340 
01341 
01342 bool ContentType::isImage()
01343 {
01344   return (strncasecmp(m_imeType.data(), "image", 5)==0);
01345 }
01346 
01347 
01348 bool ContentType::isMultipart()
01349 {
01350   return (strncasecmp(m_imeType.data(), "multipart", 9)==0);
01351 }
01352 
01353 
01354 bool ContentType::isPartial()
01355 {
01356   return (strcasecmp(m_imeType.data(), "message/partial")==0);
01357 }
01358 
01359 
01360 QCString ContentType::charset()
01361 {
01362   QCString ret=getParameter("charset");
01363   if( ret.isEmpty() || forceCS() ) { //we return the default-charset if necessary
01364     ret=defaultCS();
01365   }
01366   return ret;
01367 }
01368 
01369 
01370 void ContentType::setCharset(const QCString &s)
01371 {
01372   setParameter("charset", s);
01373 }
01374 
01375 
01376 QCString ContentType::boundary()
01377 {
01378   return getParameter("boundary");
01379 }
01380 
01381 
01382 void ContentType::setBoundary(const QCString &s)
01383 {
01384   setParameter("boundary", s, true);
01385 }
01386 
01387 
01388 QString ContentType::name()
01389 {
01390   const char *dummy=0;
01391   return ( decodeRFC2047String(getParameter("name"), &dummy, defaultCS(), forceCS()) );
01392 }
01393 
01394 
01395 void ContentType::setName(const QString &s, const QCString &cs)
01396 {
01397   e_ncCS=cs;
01398 
01399   if (isUsAscii(s)) {
01400     QCString tmp(s.latin1());
01401     addQuotes(tmp, true);
01402     setParameter("name", tmp, false);
01403   } else {
01404     // FIXME: encoded words can't be enclosed in quotes!!
01405     setParameter("name", encodeRFC2047String(s, cs), true);
01406   }
01407 }
01408 
01409 
01410 QCString ContentType::id()
01411 {
01412   return (getParameter("id"));
01413 }
01414 
01415 
01416 void ContentType::setId(const QCString &s)
01417 {
01418   setParameter("id", s, true);
01419 }
01420 
01421 
01422 int ContentType::partialNumber()
01423 {
01424   QCString p=getParameter("number");
01425   if(!p.isEmpty())
01426     return p.toInt();
01427   else
01428     return -1;
01429 }
01430 
01431 
01432 int ContentType::partialCount()
01433 {
01434   QCString p=getParameter("total");
01435   if(!p.isEmpty())
01436     return p.toInt();
01437   else
01438     return -1;
01439 }
01440 
01441 
01442 void ContentType::setPartialParams(int total, int number)
01443 {
01444   QCString num;
01445   num.setNum(number);
01446   setParameter("number", num);
01447   num.setNum(total);
01448   setParameter("total", num);
01449 }
01450 
01451 
01452 QCString ContentType::getParameter(const char *name)
01453 {
01454   QCString ret;
01455   int pos1=0, pos2=0;
01456   pos1=p_arams.find(name, 0, false);
01457   if(pos1!=-1) {
01458     if( (pos2=p_arams.find(';', pos1))==-1 )
01459       pos2=p_arams.length();
01460     pos1+=strlen(name)+1;
01461     ret=p_arams.mid(pos1, pos2-pos1);
01462     removeQuots(ret);
01463   }
01464   return ret;
01465 }
01466 
01467 
01468 void ContentType::setParameter(const QCString &name, const QCString &value, bool doubleQuotes)
01469 {
01470   int pos1=0, pos2=0;
01471   QCString param;
01472 
01473   if(doubleQuotes)
01474     param=name+"=\""+value+"\"";
01475   else
01476     param=name+"="+value;
01477 
01478   pos1=p_arams.find(name, 0, false);
01479   if(pos1==-1) {
01480     p_arams+="; "+param;
01481   }
01482   else {
01483     pos2=p_arams.find(';', pos1);
01484     if(pos2==-1)
01485       pos2=p_arams.length();
01486     p_arams.remove(pos1, pos2-pos1);
01487     p_arams.insert(pos1, param);
01488   }
01489 }
01490 
01491 //-----</Content-Type>-------------------------
01492 
01493 
01494 
01495 //-----<CTEncoding>----------------------------
01496 
01497 typedef struct { const char *s; int e; } encTableType;
01498 
01499 static const encTableType encTable[] = {  { "7Bit", CE7Bit },
01500                                           { "8Bit", CE8Bit },
01501                                           { "quoted-printable", CEquPr },
01502                                           { "base64", CEbase64 },
01503                                           { "x-uuencode", CEuuenc },
01504                                           { "binary", CEbinary },
01505                                           { 0, 0} };
01506 
01507 
01508 void CTEncoding::from7BitString(const QCString &s)
01509 {
01510   QCString stripped(s.simplifyWhiteSpace());
01511   c_te=CE7Bit;
01512   for(int i=0; encTable[i].s!=0; i++)
01513     if(strcasecmp(stripped.data(), encTable[i].s)==0) {
01514       c_te=(contentEncoding)encTable[i].e;
01515       break;
01516     }
01517   d_ecoded=( c_te==CE7Bit || c_te==CE8Bit );
01518 
01519   e_ncCS=cachedCharset(Latin1);
01520 }
01521 
01522 
01523 QCString CTEncoding::as7BitString(bool incType)
01524 {
01525   QCString str;
01526   for(int i=0; encTable[i].s!=0; i++)
01527     if(c_te==encTable[i].e) {
01528       str=encTable[i].s;
01529       break;
01530     }
01531 
01532   if(incType)
01533     return ( typeIntro()+str );
01534   else
01535     return str;
01536 }
01537 
01538 
01539 void CTEncoding::fromUnicodeString(const QString &s, const QCString&)
01540 {
01541   from7BitString( QCString(s.latin1()) );
01542 }
01543 
01544 
01545 QString CTEncoding::asUnicodeString()
01546 {
01547   return QString::fromLatin1(as7BitString(false));
01548 }
01549 
01550 //-----</CTEncoding>---------------------------
01551 
01552 
01553 
01554 //-----<CDisposition>--------------------------
01555 
01556 void CDisposition::from7BitString(const QCString &s)
01557 {
01558   if(strncasecmp(s.data(), "attachment", 10)==0)
01559     d_isp=CDattachment;
01560   else d_isp=CDinline;
01561 
01562   int pos=s.find("filename=", 0, false);
01563   QCString fn;
01564   if(pos>-1) {
01565     pos+=9;
01566     fn=s.mid(pos, s.length()-pos);
01567     removeQuots(fn);
01568     f_ilename=decodeRFC2047String(fn, &e_ncCS, defaultCS(), forceCS());
01569   }
01570 }
01571 
01572 
01573 QCString CDisposition::as7BitString(bool incType)
01574 {
01575   QCString ret;
01576   if(d_isp==CDattachment)
01577     ret="attachment";
01578   else
01579     ret="inline";
01580 
01581   if(!f_ilename.isEmpty()) {
01582     if (isUsAscii(f_ilename)) {
01583       QCString tmp(f_ilename.latin1());
01584       addQuotes(tmp, true);
01585       ret+="; filename="+tmp;
01586     } else {
01587       // FIXME: encoded words can't be enclosed in quotes!!
01588       ret+="; filename=\""+encodeRFC2047String(f_ilename, e_ncCS)+"\"";
01589     }
01590   }
01591 
01592   if(incType)
01593     return ( typeIntro()+ret );
01594   else
01595     return ret;
01596 }
01597 
01598 
01599 void CDisposition::fromUnicodeString(const QString &s, const QCString &cs)
01600 {
01601   if(strncasecmp(s.latin1(), "attachment", 10)==0)
01602     d_isp=CDattachment;
01603   else d_isp=CDinline;
01604 
01605   int pos=s.find("filename=", 0, false);
01606   if(pos>-1) {
01607     pos+=9;
01608     f_ilename=s.mid(pos, s.length()-pos);
01609     removeQuots(f_ilename);
01610   }
01611 
01612   e_ncCS=cachedCharset(cs);
01613 }
01614 
01615 
01616 QString CDisposition::asUnicodeString()
01617 {
01618   QString ret;
01619   if(d_isp==CDattachment)
01620     ret="attachment";
01621   else
01622     ret="inline";
01623 
01624   if(!f_ilename.isEmpty())
01625     ret+="; filename=\""+f_ilename+"\"";
01626 
01627   return ret;
01628 }
01629 
01630 //-----</CDisposition>-------------------------
01631 #endif
01632 } // namespace Headers
01633 
01634 } // namespace KMime
KDE Home | KDE Accessibility Home | Description of Access Keys