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.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Oct 21 19:46:16 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003