libkdenetwork Library API Documentation

kmime_content.cpp

00001 /*
00002     kmime_content.cpp
00003 
00004     KMime, the KDE internet mail/usenet news message library.
00005     Copyright (c) 2001 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, US
00015 */
00016 #include "kmime_content.h"
00017 #include "kmime_parsers.h"
00018 
00019 #include <kcharsets.h>
00020 #include <kmdcodec.h>
00021 #include <kglobal.h>
00022 #include <klocale.h>
00023 #include <kdebug.h>
00024 
00025 #include <qtextcodec.h>
00026 
00027 using namespace KMime;
00028 
00029 namespace KMime {
00030 
00031 Content::Content()
00032  : c_ontents(0), h_eaders(0), f_orceDefaultCS(false)
00033 {
00034   d_efaultCS = cachedCharset("ISO-8859-1");
00035 }
00036 
00037 
00038 Content::Content(const QCString &h, const QCString &b)
00039  : c_ontents(0), h_eaders(0), f_orceDefaultCS(false)
00040 {
00041   d_efaultCS = cachedCharset("ISO-8859-1");
00042   h_ead=h.copy();
00043   b_ody=b.copy();
00044 }
00045 
00046 
00047 Content::~Content()
00048 {
00049   delete c_ontents;
00050   delete h_eaders;
00051 }
00052 
00053 
00054 void Content::setContent(QStrList *l)
00055 {
00056   //qDebug("Content::setContent(QStrList *l) : start");
00057   h_ead.resize(0);
00058   b_ody.resize(0);
00059 
00060   //usage of textstreams is much faster than simply appending the strings
00061   QTextStream hts(h_ead, IO_WriteOnly),
00062               bts(b_ody, IO_WriteOnly);
00063   hts.setEncoding(QTextStream::Latin1);
00064   bts.setEncoding(QTextStream::Latin1);
00065 
00066   bool isHead=true;
00067   for(char *line=l->first(); line; line=l->next()) {
00068     if(isHead && line[0]=='\0') {
00069       isHead=false;
00070       continue;
00071     }
00072     if(isHead)
00073       hts << line << "\n";
00074     else
00075       bts << line << "\n";
00076   }
00077 
00078   //terminate strings
00079   hts << '\0';
00080   bts << '\0';
00081 
00082   //qDebug("Content::setContent(QStrList *l) : finished");
00083 }
00084 
00085 
00086 void Content::setContent(const QCString &s)
00087 {
00088   int pos=s.find("\n\n", 0);
00089   if(pos>-1) {
00090     h_ead=s.left(++pos);  //header *must* end with "\n" !!
00091     b_ody=s.mid(++pos, s.length()-pos);
00092   }
00093   else
00094     h_ead=s;
00095 }
00096 
00097 
00098 //parse the message, split multiple parts
00099 void Content::parse()
00100 {
00101   //qDebug("void Content::parse() : start");
00102   delete h_eaders;
00103   h_eaders=0;
00104   
00105   // check this part has already been partioned into subparts.
00106   // if this is the case, we will not try to reparse the body
00107   // of this part.
00108   if ((b_ody.size() == 0) && (c_ontents != 0) && !c_ontents->isEmpty()) {
00109     // reparse all sub parts
00110     for(Content *c=c_ontents->first(); c; c=c_ontents->next())
00111       c->parse();
00112     return;
00113   }    
00114   
00115   delete c_ontents;
00116   c_ontents=0;
00117 
00118   Headers::ContentType *ct=contentType();
00119   QCString tmp;
00120   Content *c;
00121   Headers::contentCategory cat;
00122 
00123   // just "text" as mimetype is suspicious, perhaps this article was
00124   // generated by broken software, better check for uuencoded binaries
00125   if (ct->mimeType()=="text")
00126     ct->setMimeType("invalid/invalid");
00127 
00128   if(ct->isText())
00129     return; //nothing to do
00130 
00131   if(ct->isMultipart()) {   //this is a multipart message
00132     tmp=ct->boundary(); //get boundary-parameter
00133 
00134     if(!tmp.isEmpty()) {
00135       Parser::MultiPart mpp(b_ody, tmp);
00136       if(mpp.parse()) { //at least one part found
00137 
00138         c_ontents=new List();
00139         c_ontents->setAutoDelete(true);
00140 
00141         if(ct->isSubtype("alternative")) //examine category for the sub-parts
00142           cat=Headers::CCalternativePart;
00143         else
00144           cat=Headers::CCmixedPart;  //default to "mixed"
00145 
00146         QCStringList parts=mpp.parts();
00147         QCStringList::Iterator it;
00148         for(it=parts.begin(); it!=parts.end(); ++it) { //create a new Content for every part
00149           c=new Content();
00150           c->setContent(*it);
00151           c->parse();
00152           c->contentType()->setCategory(cat); //set category of the sub-part
00153           c_ontents->append(c);
00154           //qDebug("part:\n%s\n\n%s", c->h_ead.data(), c->b_ody.left(100).data());
00155         }
00156 
00157         //the whole content is now split into single parts, so it's safe delete the message-body
00158         b_ody.resize(0);
00159       }
00160       else { //sh*t, the parsing failed so we have to treat the message as "text/plain" instead
00161         ct->setMimeType("text/plain");
00162         ct->setCharset("US-ASCII");
00163       }
00164     }
00165   }
00166   else if (ct->mimeType()=="invalid/invalid") { //non-mime body => check for uuencoded content
00167     Parser::UUEncoded uup(b_ody, rawHeader("Subject"));
00168 
00169     if(uup.parse()) { // yep, it is uuencoded
00170 
00171       if(uup.isPartial()) {  // this seems to be only a part of the message so we treat it as "message/partial"
00172         ct->setMimeType("message/partial");
00173         //ct->setId(uniqueString()); not needed yet
00174         ct->setPartialParams(uup.partialCount(), uup.partialNumber());
00175         contentTransferEncoding()->setCte(Headers::CE7Bit);
00176       }
00177       else { //it's a complete message => treat as "multipart/mixed"
00178         //the whole content is now split into single parts, so it's safe to delete the message-body
00179         b_ody.resize(0);
00180 
00181         //binary parts
00182         for (unsigned int i=0;i<uup.binaryParts().count();i++) {
00183           c=new Content();
00184           //generate content with mime-compliant headers
00185           tmp="Content-Type: ";
00186           tmp += uup.mimeTypes().at(i);
00187           tmp += "; name=\"";
00188           tmp += uup.filenames().at(i);
00189           tmp += "\"\nContent-Transfer-Encoding: x-uuencode\nContent-Disposition: attachment; filename=\"";
00190           tmp += uup.filenames().at(i);
00191           tmp += "\"\n\n";
00192           tmp += uup.binaryParts().at(i);
00193           c->setContent(tmp);
00194           addContent(c);
00195         }
00196 
00197         if(c_ontents && c_ontents->first()) { //readd the plain text before the uuencoded part
00198           c_ontents->first()->setContent("Content-Type: text/plain\nContent-Transfer-Encoding: 7Bit\n\n"+uup.textPart());
00199           c_ontents->first()->contentType()->setMimeType("text/plain");
00200         }
00201       }
00202     } else {
00203       Parser::YENCEncoded yenc(b_ody);
00204  
00205       if ( yenc.parse()) {
00206         /* If it is partial, just assume there is exactly one decoded part,
00207          * and make this that part */
00208         if (yenc.isPartial()) {
00209           ct->setMimeType("message/partial");
00210           //ct->setId(uniqueString()); not needed yet
00211           ct->setPartialParams(yenc.partialCount(), yenc.partialNumber());
00212           contentTransferEncoding()->setCte(Headers::CEbinary);
00213         }
00214         else { //it's a complete message => treat as "multipart/mixed"
00215           //the whole content is now split into single parts, so it's safe to delete the message-body
00216           b_ody.resize(0);
00217 
00218           //binary parts
00219           for (unsigned int i=0;i<yenc.binaryParts().count();i++) {
00220             c=new Content();
00221             //generate content with mime-compliant headers
00222             tmp="Content-Type: ";
00223             tmp += yenc.mimeTypes().at(i);
00224             tmp += "; name=\"";
00225             tmp += yenc.filenames().at(i);
00226             tmp += "\"\nContent-Transfer-Encoding: binary\nContent-Disposition: attachment; filename=\"";
00227             tmp += yenc.filenames().at(i);
00228             tmp += "\"\n\n";
00229             c->setContent(tmp);
00230             
00231             // the bodies of yenc message parts are binary data, not null-terminated strings:            
00232             QByteArray body = yenc.binaryParts()[i];
00233             QCString body_string(body.size());
00234             memcpy(body_string.data(), body.data(), body.size());
00235             c->setBody(body_string);            
00236     
00237             addContent(c);
00238           }
00239 
00240           if(c_ontents && c_ontents->first()) { //readd the plain text before the uuencoded part
00241             c_ontents->first()->setContent("Content-Type: text/plain\nContent-Transfer-Encoding: 7Bit\n\n"+yenc.textPart());
00242             c_ontents->first()->contentType()->setMimeType("text/plain");
00243           }
00244         }
00245       }    
00246       else { //no, this doesn't look like uuencoded stuff => we treat it as "text/plain"        
00247         ct->setMimeType("text/plain");
00248       }
00249     }
00250   }
00251 
00252   //qDebug("void Content::parse() : finished");
00253 }
00254 
00255 
00256 void Content::assemble()
00257 {
00258   QCString newHead="";
00259 
00260   //Content-Type
00261   newHead+=contentType()->as7BitString()+"\n";
00262 
00263   //Content-Transfer-Encoding
00264   newHead+=contentTransferEncoding()->as7BitString()+"\n";
00265 
00266   //Content-Description
00267   Headers::Base *h=contentDescription(false);
00268   if(h)
00269     newHead+=h->as7BitString()+"\n";
00270 
00271   //Content-Disposition
00272   h=contentDisposition(false);
00273   if(h)
00274     newHead+=h->as7BitString()+"\n";
00275 
00276   h_ead=newHead;
00277 }
00278 
00279 
00280 void Content::clear()
00281 {
00282   delete h_eaders;
00283   h_eaders=0;
00284   delete c_ontents;
00285   c_ontents=0;
00286   h_ead.resize(0);
00287   b_ody.resize(0);
00288 }
00289 
00290 
00291 QCString Content::encodedContent(bool useCrLf)
00292 {
00293   QCString e;
00294 
00295   // hack to convert articles with uuencoded or yencoded binaries into
00296   // proper mime-compliant articles
00297   if(c_ontents && !c_ontents->isEmpty()) {
00298     bool convertNonMimeBinaries=false;
00299 
00300     // reencode non-mime binaries...
00301     for(Content *c=c_ontents->first(); c; c=c_ontents->next()) {
00302       if ((c->contentTransferEncoding(true)->cte()==Headers::CEuuenc) ||
00303           (c->contentTransferEncoding(true)->cte()==Headers::CEbinary)) {
00304         convertNonMimeBinaries=true;
00305         c->b_ody = KCodecs::base64Encode(c->decodedContent(), true);
00306         c->b_ody.append("\n");
00307         c->contentTransferEncoding(true)->setCte(Headers::CEbase64);
00308         c->contentTransferEncoding(true)->setDecoded(false);
00309         c->removeHeader("Content-Description");
00310         c->assemble();
00311       }
00312     }
00313 
00314     // add proper mime headers...
00315     if (convertNonMimeBinaries) {
00316       h_ead.replace(QRegExp("MIME-Version: .*\\n"),"");
00317       h_ead.replace(QRegExp("Content-Type: .*\\n"),"");
00318       h_ead.replace(QRegExp("Content-Transfer-Encoding: .*\\n"),"");
00319       h_ead+="MIME-Version: 1.0\n";
00320       h_ead+=contentType(true)->as7BitString()+"\n";
00321       h_ead+=contentTransferEncoding(true)->as7BitString()+"\n";
00322     }
00323   }
00324 
00325   //head
00326   e=h_ead.copy();
00327   e+="\n";
00328 
00329   //body
00330   if(!b_ody.isEmpty()) { //this message contains only one part
00331     Headers::CTEncoding *enc=contentTransferEncoding();
00332 
00333     if(enc->needToEncode()) {
00334       if(enc->cte()==Headers::CEquPr) {
00335         QByteArray temp(b_ody.length());
00336         memcpy(temp.data(), b_ody.data(), b_ody.length());
00337         e+=KCodecs::quotedPrintableEncode(temp, false);
00338       } else {
00339         e+=KCodecs::base64Encode(b_ody, true);
00340         e+="\n";
00341       }
00342     }
00343     else
00344       e+=b_ody;
00345   }
00346   else if(c_ontents && !c_ontents->isEmpty()) { //this is a multipart message
00347     Headers::ContentType *ct=contentType();
00348     QCString boundary="--"+ct->boundary();
00349 
00350     //add all (encoded) contents separated by boundaries
00351     for(Content *c=c_ontents->first(); c; c=c_ontents->next()) {
00352       e+=boundary+"\n";
00353       e+=c->encodedContent(false);  // don't convert LFs here, we do that later!!!!!
00354     }
00355     //finally append the closing boundary
00356     e+=boundary+"--\n";
00357   };
00358 
00359   if(useCrLf)
00360     return LFtoCRLF(e);
00361   else
00362     return e;
00363 }
00364 
00365 
00366 QByteArray Content::decodedContent()
00367 {
00368   QByteArray temp, ret;
00369   Headers::CTEncoding *ec=contentTransferEncoding();
00370   bool removeTrailingNewline=false;
00371   int size=ec->cte()==Headers::CEbinary ? b_ody.size() : b_ody.length();
00372   
00373   if (size==0)
00374     return ret;
00375 
00376   temp.resize(size);
00377   memcpy(temp.data(), b_ody.data(), size);
00378 
00379   if(ec->decoded()) {
00380     ret = temp;
00381     removeTrailingNewline=true;
00382   } else {
00383     switch(ec->cte()) {
00384       case Headers::CEbase64 :
00385         KCodecs::base64Decode(temp, ret);
00386       break;
00387       case Headers::CEquPr :
00388         ret = KCodecs::quotedPrintableDecode(b_ody);
00389         ret.resize(ret.size()-1);  // remove null-char
00390         removeTrailingNewline=true;
00391       break;
00392       case Headers::CEuuenc :
00393         KCodecs::uudecode(temp, ret);
00394       break;
00395       case Headers::CEbinary :
00396         ret = temp;
00397         removeTrailingNewline=false;
00398       default :
00399         ret = temp;
00400         removeTrailingNewline=true;
00401     }
00402   }
00403 
00404   if (removeTrailingNewline && (ret.size()>0) && (ret[ret.size()-1] == '\n'))
00405     ret.resize(ret.size()-1);
00406 
00407   return ret;
00408 }
00409 
00410 
00411 void Content::decodedText(QString &s, bool trimText,
00412               bool removeTrailingNewlines)
00413 {
00414   if(!decodeText()) //this is not a text content !!
00415     return;
00416 
00417   bool ok=true;
00418   QTextCodec *codec=KGlobal::charsets()->codecForName(contentType()->charset(),ok);
00419 
00420   s=codec->toUnicode(b_ody.data(), b_ody.length());
00421 
00422   if (trimText && removeTrailingNewlines) {
00423     int i;
00424     for (i=s.length()-1; i>=0; i--)
00425       if (!s[i].isSpace())
00426         break;
00427     s.truncate(i+1);
00428   } else {
00429     if (s.right(1)=="\n")
00430       s.truncate(s.length()-1);    // remove trailing new-line
00431   }
00432 }
00433 
00434 
00435 void Content::decodedText(QStringList &l, bool trimText,
00436               bool removeTrailingNewlines)
00437 {
00438   if(!decodeText()) //this is not a text content !!
00439     return;
00440 
00441   QString unicode;
00442   bool ok=true;
00443 
00444   QTextCodec *codec=KGlobal::charsets()->codecForName(contentType()->charset(),ok);
00445 
00446   unicode=codec->toUnicode(b_ody.data(), b_ody.length());
00447 
00448   if (trimText && removeTrailingNewlines) {
00449     int i;
00450     for (i=unicode.length()-1; i>=0; i--)
00451       if (!unicode[i].isSpace())
00452         break;
00453     unicode.truncate(i+1);
00454   } else {
00455     if (unicode.right(1)=="\n")
00456       unicode.truncate(unicode.length()-1);    // remove trailing new-line
00457   }
00458 
00459   l=QStringList::split('\n', unicode, true); //split the string at linebreaks
00460 }
00461 
00462 
00463 void Content::fromUnicodeString(const QString &s)
00464 {
00465   bool ok=true;
00466   QTextCodec *codec=KGlobal::charsets()->codecForName(contentType()->charset(),ok);
00467 
00468   if(!ok) { // no suitable codec found => try local settings and hope the best ;-)
00469     codec=KGlobal::locale()->codecForEncoding();
00470     QCString chset=KGlobal::locale()->encoding();
00471     contentType()->setCharset(chset);
00472   }
00473 
00474   b_ody=codec->fromUnicode(s);
00475   contentTransferEncoding()->setDecoded(true); //text is always decoded
00476 }
00477 
00478 
00479 Content* Content::textContent()
00480 {
00481   Content *ret=0;
00482 
00483   //return the first content with mimetype=text/*
00484   if(contentType()->isText())
00485     ret=this;
00486   else if(c_ontents)
00487     for(Content *c=c_ontents->first(); c; c=c_ontents->next())
00488       if( (ret=c->textContent())!=0 )
00489         break;
00490 
00491   return ret;
00492 }
00493 
00494 
00495 void Content::attachments(Content::List *dst, bool incAlternatives)
00496 {
00497   dst->setAutoDelete(false); //don't delete the contents
00498 
00499   if(!c_ontents)
00500     dst->append(this);
00501   else {
00502     for(Content *c=c_ontents->first(); c; c=c_ontents->next()) {
00503       if( !incAlternatives && c->contentType()->category()==Headers::CCalternativePart)
00504         continue;
00505       else
00506         c->attachments(dst, incAlternatives);
00507     }
00508   }
00509 
00510   if(type()!=ATmimeContent) { // this is the toplevel article
00511     Content *text=textContent();
00512     if(text)
00513       dst->removeRef(text);
00514   }
00515 }
00516 
00517 
00518 void Content::addContent(Content *c, bool prepend)
00519 {
00520   if(!c_ontents) { // this message is not multipart yet
00521     c_ontents=new List();
00522     c_ontents->setAutoDelete(true);
00523 
00524     // first we convert the body to a content
00525     Content *main=new Content();
00526 
00527     //the Mime-Headers are needed, so we move them to the new content
00528     if(h_eaders) {
00529 
00530       main->h_eaders=new Headers::Base::List();
00531       main->h_eaders->setAutoDelete(true);
00532 
00533       Headers::Base::List srcHdrs=(*h_eaders);
00534       srcHdrs.setAutoDelete(false);
00535       int idx=0;
00536       for(Headers::Base *h=srcHdrs.first(); h; h=srcHdrs.next()) {
00537         if(h->isMimeHeader()) {
00538           //remove from this content
00539           idx=h_eaders->findRef(h);
00540           h_eaders->take(idx);
00541           //append to new content
00542           main->h_eaders->append(h);
00543         }
00544       }
00545     }
00546 
00547     //"main" is now part of a multipart/mixed message
00548     main->contentType()->setCategory(Headers::CCmixedPart);
00549 
00550     //the head of "main" is empty, so we assemble it
00551     main->assemble();
00552 
00553     //now we can copy the body and append the new content;
00554     main->b_ody=b_ody.copy();
00555     c_ontents->append(main);
00556     b_ody.resize(0); //not longer needed
00557 
00558 
00559     //finally we have to convert this article to "multipart/mixed"
00560     Headers::ContentType *ct=contentType();
00561     ct->setMimeType("multipart/mixed");
00562     ct->setBoundary(multiPartBoundary());
00563     ct->setCategory(Headers::CCcontainer);
00564     contentTransferEncoding()->clear();  // 7Bit, decoded
00565 
00566   }
00567   //here we actually add the content
00568   if(prepend)
00569     c_ontents->insert(0, c);
00570   else
00571     c_ontents->append(c);
00572 }
00573 
00574 
00575 void Content::removeContent(Content *c, bool del)
00576 {
00577   if(!c_ontents) // what the ..
00578     return;
00579 
00580   int idx=0;
00581   if(del)
00582     c_ontents->removeRef(c);
00583   else {
00584     idx=c_ontents->findRef(c);
00585     c_ontents->take(idx);
00586   }
00587 
00588   //only one content left => turn this message in a single-part
00589   if(c_ontents->count()==1) {
00590     Content *main=c_ontents->first();
00591 
00592     //first we have to move the mime-headers
00593     if(main->h_eaders) {
00594       if(!h_eaders) {
00595         h_eaders=new Headers::Base::List();
00596         h_eaders->setAutoDelete(true);
00597       }
00598 
00599       Headers::Base::List mainHdrs=(*(main->h_eaders));
00600       mainHdrs.setAutoDelete(false);
00601 
00602       for(Headers::Base *h=mainHdrs.first(); h; h=mainHdrs.next()) {
00603         if(h->isMimeHeader()) {
00604           removeHeader(h->type()); //remove the old header first
00605           h_eaders->append(h); //now append the new one
00606           idx=main->h_eaders->findRef(h);
00607           main->h_eaders->take(idx); //remove from the old content
00608           kdDebug(5003) << "Content::removeContent(Content *c, bool del) : mime-header moved: "
00609                         << h->as7BitString() << endl;
00610         }
00611       }
00612     }
00613 
00614     //now we can copy the body
00615     b_ody=main->b_ody.copy();
00616 
00617     //finally we can delete the content list
00618     delete c_ontents;
00619     c_ontents=0;
00620   }
00621 }
00622 
00623 
00624 void Content::changeEncoding(Headers::contentEncoding e)
00625 {
00626   Headers::CTEncoding *enc=contentTransferEncoding();
00627   if(enc->cte()==e) //nothing to do
00628     return;
00629 
00630   if(decodeText())
00631     enc->setCte(e); // text is not encoded until it's sent or saved so we just set the new encoding
00632   else { // this content contains non textual data, that has to be re-encoded
00633 
00634     if(e!=Headers::CEbase64) {
00635       //kdWarning(5003) << "Content::changeEncoding() : non textual data and encoding != base64 - this should not happen\n => forcing base64" << endl;
00636       e=Headers::CEbase64;
00637     }
00638 
00639     if(enc->cte()!=e) { // ok, we reencode the content using base64
00640       b_ody = KCodecs::base64Encode(decodedContent(), true);
00641       b_ody.append("\n");
00642       enc->setCte(e); //set encoding
00643       enc->setDecoded(false);
00644     }
00645   }
00646 }
00647 
00648 
00649 void Content::toStream(QTextStream &ts, bool scrambleFromLines)
00650 {
00651   QCString ret=encodedContent(false);
00652 
00653   if (scrambleFromLines)
00654     ret.replace(QRegExp("\\n\\nFrom "), "\n\n>From ");
00655 
00656   ts << ret;
00657 }
00658 
00659 
00660 Headers::Generic*  Content::getNextHeader(QCString &head)
00661 {
00662   int pos1=-1, pos2=0, len=head.length()-1;
00663   bool folded(false);
00664   Headers::Generic *header=0;
00665 
00666   pos1 = head.find(": ");
00667 
00668   if (pos1>-1) {    //there is another header
00669     pos2=pos1+=2; //skip the name
00670 
00671     if (head[pos2]!='\n') {  // check if the header is not empty
00672       while(1) {
00673         pos2=head.find("\n", pos2+1);
00674         if(pos2==-1 || pos2==len || ( head[pos2+1]!=' ' && head[pos2+1]!='\t') ) //break if we reach the end of the string, honor folded lines
00675           break;
00676         else
00677           folded = true;
00678       }
00679     }
00680 
00681     if(pos2<0) pos2=len+1; //take the rest of the string
00682 
00683     if (!folded)
00684       header = new Headers::Generic(head.left(pos1-2), this, head.mid(pos1, pos2-pos1));
00685     else
00686       header = new Headers::Generic(head.left(pos1-2), this, head.mid(pos1, pos2-pos1).replace(QRegExp("\\s*\\n\\s*")," "));
00687 
00688     head.remove(0,pos2+1);
00689   }
00690   else {
00691     head = "";
00692   }
00693 
00694   return header;
00695 }
00696 
00697 
00698 Headers::Base* Content::getHeaderByType(const char *type)
00699 {
00700   if(!type)
00701     return 0;
00702 
00703   Headers::Base *h=0;
00704   //first we check if the requested header is already cached
00705   if(h_eaders)
00706     for(h=h_eaders->first(); h; h=h_eaders->next())
00707       if(h->is(type)) return h; //found
00708 
00709   //now we look for it in the article head
00710   QCString raw=rawHeader(type);
00711   if(!raw.isEmpty()) { //ok, we found it
00712     //choose a suitable header class
00713     if(strcasecmp("Message-Id", type)==0)
00714       h=new Headers::MessageID(this, raw);
00715     else if(strcasecmp("Subject", type)==0)
00716       h=new Headers::Subject(this, raw);
00717     else if(strcasecmp("Date", type)==0)
00718       h=new Headers::Date(this, raw);
00719     else if(strcasecmp("From", type)==0)
00720       h=new Headers::From(this, raw);
00721     else if(strcasecmp("Organization", type)==0)
00722       h=new Headers::Organization(this, raw);
00723     else if(strcasecmp("Reply-To", type)==0)
00724       h=new Headers::ReplyTo(this, raw);
00725     else if(strcasecmp("Mail-Copies-To", type)==0)
00726       h=new Headers::MailCopiesTo(this, raw);
00727     else if(strcasecmp("To", type)==0)
00728       h=new Headers::To(this, raw);
00729     else if(strcasecmp("CC", type)==0)
00730       h=new Headers::CC(this, raw);
00731     else if(strcasecmp("BCC", type)==0)
00732       h=new Headers::BCC(this, raw);
00733     else if(strcasecmp("Newsgroups", type)==0)
00734       h=new Headers::Newsgroups(this, raw);
00735     else if(strcasecmp("Followup-To", type)==0)
00736       h=new Headers::FollowUpTo(this, raw);
00737     else if(strcasecmp("References", type)==0)
00738       h=new Headers::References(this, raw);
00739     else if(strcasecmp("Lines", type)==0)
00740       h=new Headers::Lines(this, raw);
00741     else if(strcasecmp("Content-Type", type)==0)
00742       h=new Headers::ContentType(this, raw);
00743     else if(strcasecmp("Content-Transfer-Encoding", type)==0)
00744       h=new Headers::CTEncoding(this, raw);
00745     else if(strcasecmp("Content-Disposition", type)==0)
00746       h=new Headers::CDisposition(this, raw);
00747     else if(strcasecmp("Content-Description", type)==0)
00748       h=new Headers::CDescription(this, raw);
00749     else
00750       h=new Headers::Generic(type, this, raw);
00751 
00752     if(!h_eaders) {
00753       h_eaders=new Headers::Base::List();
00754       h_eaders->setAutoDelete(true);
00755     }
00756 
00757     h_eaders->append(h);  //add to cache
00758     return h;
00759   }
00760   else
00761     return 0; //header not found
00762 }
00763 
00764 
00765 void Content::setHeader(Headers::Base *h)
00766 {
00767   if(!h) return;
00768   removeHeader(h->type());
00769   if(!h_eaders) {
00770     h_eaders=new Headers::Base::List();
00771     h_eaders->setAutoDelete(true);
00772   }
00773   h_eaders->append(h);
00774 }
00775 
00776 
00777 bool Content::removeHeader(const char *type)
00778 {
00779   if(h_eaders)
00780     for(Headers::Base *h=h_eaders->first(); h; h=h_eaders->next())
00781       if(h->is(type))
00782         return h_eaders->remove();
00783 
00784   return false;
00785 }
00786 
00787 
00788 int Content::size()
00789 {
00790   int ret=b_ody.length();
00791 
00792   if(contentTransferEncoding()->cte()==Headers::CEbase64)
00793     return (ret*3/4); //base64 => 6 bit per byte
00794 
00795   return ret;
00796 }
00797 
00798 
00799 int Content::storageSize()
00800 {
00801   int s=h_ead.size();
00802 
00803   if(!c_ontents)
00804     s+=b_ody.size();
00805   else {
00806     for(Content *c=c_ontents->first(); c; c=c_ontents->next())
00807       s+=c->storageSize();
00808   }
00809 
00810   return s;
00811 }
00812 
00813 
00814 int Content::lineCount()
00815 {
00816   int ret=0;
00817   if(type()==ATmimeContent)
00818     ret+=h_ead.contains('\n');
00819   ret+=b_ody.contains('\n');
00820 
00821   if(c_ontents && !c_ontents->isEmpty())
00822     for(Content *c=c_ontents->first(); c; c=c_ontents->next())
00823       ret+=c->lineCount();
00824 
00825   return ret;
00826 }
00827 
00828 
00829 QCString Content::rawHeader(const char *name)
00830 {
00831   return extractHeader(h_ead, name);
00832 }
00833 
00834 
00835 bool Content::decodeText()
00836 {
00837   Headers::CTEncoding *enc=contentTransferEncoding();
00838 
00839   if(!contentType()->isText())
00840     return false; //non textual data cannot be decoded here => use decodedContent() instead
00841   if(enc->decoded())
00842     return true; //nothing to do
00843 
00844   switch(enc->cte()) {
00845     case Headers::CEbase64 :
00846       b_ody=KCodecs::base64Decode(b_ody);
00847       b_ody.append("\n");
00848     break;
00849     case Headers::CEquPr :
00850       b_ody=KCodecs::quotedPrintableDecode(b_ody);
00851     break;
00852     case Headers::CEuuenc :
00853       b_ody=KCodecs::uudecode(b_ody);
00854       b_ody.append("\n");
00855     break;
00856     case Headers::CEbinary :
00857       b_ody=QCString(b_ody.data(), b_ody.size()+1);
00858       b_ody.append("\n");
00859     default :
00860     break;
00861   }
00862 
00863   enc->setDecoded(true);
00864   return true;
00865 }
00866 
00867 
00868 void Content::setDefaultCharset(const QCString &cs)
00869 { 
00870   d_efaultCS = KMime::cachedCharset(cs); 
00871   
00872   if(c_ontents && !c_ontents->isEmpty())
00873     for(Content *c=c_ontents->first(); c; c=c_ontents->next())
00874       c->setDefaultCharset(cs);
00875       
00876   // reparse the part and its sub-parts in order
00877   // to clear cached header values
00878   parse();      
00879 }
00880 
00881 
00882 void Content::setForceDefaultCS(bool b)
00883 {
00884   f_orceDefaultCS=b;
00885   
00886   if(c_ontents && !c_ontents->isEmpty())
00887     for(Content *c=c_ontents->first(); c; c=c_ontents->next())
00888       c->setForceDefaultCS(b);
00889   
00890   // reparse the part and its sub-parts in order
00891   // to clear cached header values    
00892   parse();
00893 }
00894 
00895 
00896 } // namespace KMime
KDE Logo
This file is part of the documentation for libkdenetwork Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu May 3 20:16:59 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003