16 #include "kmime_content.h"
17 #include "kmime_parsers.h"
19 #include <kcharsets.h>
21 #include <tdeglobal.h>
22 #include <tdelocale.h>
25 #include <tqtextcodec.h>
27 using namespace KMime;
32 : c_ontents(0), h_eaders(0), f_orceDefaultCS(false)
34 d_efaultCS = cachedCharset(
"ISO-8859-1");
38 Content::Content(
const TQCString &h,
const TQCString &b)
39 : c_ontents(0), h_eaders(0), f_orceDefaultCS(false)
41 d_efaultCS = cachedCharset(
"ISO-8859-1");
54 void Content::setContent(TQStrList *l)
61 TQTextStream hts(h_ead, IO_WriteOnly),
62 bts(b_ody, IO_WriteOnly);
63 hts.setEncoding(TQTextStream::Latin1);
64 bts.setEncoding(TQTextStream::Latin1);
67 for(
char *line=l->first(); line; line=l->next()) {
68 if(isHead && line[0]==
'\0') {
86 void Content::setContent(
const TQCString &s)
88 int pos=s.find(
"\n\n", 0);
91 b_ody=s.mid(pos+1, s.length()-pos-1);
108 if ((b_ody.size() == 0) && (c_ontents != 0) && !c_ontents->isEmpty()) {
110 for(
Content *c=c_ontents->first(); c; c=c_ontents->next())
118 Headers::ContentType *ct=contentType();
121 Headers::contentCategory cat;
125 if (ct->mimeType()==
"text")
126 ct->setMimeType(
"invalid/invalid");
131 if(ct->isMultipart()) {
138 c_ontents=
new List();
139 c_ontents->setAutoDelete(
true);
141 if(ct->isSubtype(
"alternative"))
142 cat=Headers::CCalternativePart;
144 cat=Headers::CCmixedPart;
146 QCStringList parts=mpp.parts();
147 QCStringList::Iterator it;
148 for(it=parts.begin(); it!=parts.end(); ++it) {
152 c->contentType()->setCategory(cat);
153 c_ontents->append(c);
161 ct->setMimeType(
"text/plain");
162 ct->setCharset(
"US-ASCII");
166 else if (ct->mimeType()==
"invalid/invalid") {
171 if(uup.isPartial()) {
172 ct->setMimeType(
"message/partial");
174 ct->setPartialParams(uup.partialCount(), uup.partialNumber());
175 contentTransferEncoding()->setCte(Headers::CE7Bit);
182 for (
unsigned int i=0;i<uup.binaryParts().count();i++) {
185 tmp=
"Content-Type: ";
186 tmp += uup.mimeTypes().at(i);
188 tmp += uup.filenames().at(i);
189 tmp +=
"\"\nContent-Transfer-Encoding: x-uuencode\nContent-Disposition: attachment; filename=\"";
190 tmp += uup.filenames().at(i);
192 tmp += uup.binaryParts().at(i);
197 if(c_ontents && c_ontents->first()) {
198 c_ontents->first()->setContent(
"Content-Type: text/plain\nContent-Transfer-Encoding: 7Bit\n\n"+uup.textPart());
199 c_ontents->first()->contentType()->setMimeType(
"text/plain");
208 if (yenc.isPartial()) {
209 ct->setMimeType(
"message/partial");
211 ct->setPartialParams(yenc.partialCount(), yenc.partialNumber());
212 contentTransferEncoding()->setCte(Headers::CEbinary);
219 for (
unsigned int i=0;i<yenc.binaryParts().count();i++) {
222 tmp=
"Content-Type: ";
223 tmp += yenc.mimeTypes().at(i);
225 tmp += yenc.filenames().at(i);
226 tmp +=
"\"\nContent-Transfer-Encoding: binary\nContent-Disposition: attachment; filename=\"";
227 tmp += yenc.filenames().at(i);
232 TQByteArray body = yenc.binaryParts()[i];
233 TQCString body_string(body.size());
234 memcpy(body_string.data(), body.data(), body.size());
235 c->setBody(body_string);
240 if(c_ontents && c_ontents->first()) {
241 c_ontents->first()->setContent(
"Content-Type: text/plain\nContent-Transfer-Encoding: 7Bit\n\n"+yenc.textPart());
242 c_ontents->first()->contentType()->setMimeType(
"text/plain");
247 ct->setMimeType(
"text/plain");
256 void Content::assemble()
258 TQCString newHead=
"";
261 newHead+=contentType()->as7BitString()+
"\n";
264 newHead+=contentTransferEncoding()->as7BitString()+
"\n";
272 h=contentDisposition(
false);
280 void Content::clear()
291 TQCString Content::encodedContent(
bool useCrLf)
297 if(c_ontents && !c_ontents->isEmpty()) {
298 bool convertNonMimeBinaries=
false;
301 for(
Content *c=c_ontents->first(); c; c=c_ontents->next()) {
302 if ((c->contentTransferEncoding(
true)->cte()==Headers::CEuuenc) ||
303 (c->contentTransferEncoding(
true)->cte()==Headers::CEbinary)) {
304 convertNonMimeBinaries=
true;
305 c->b_ody = KCodecs::base64Encode(c->decodedContent(),
true);
306 c->b_ody.append(
"\n");
307 c->contentTransferEncoding(
true)->setCte(Headers::CEbase64);
308 c->contentTransferEncoding(
true)->setDecoded(
false);
309 c->removeHeader(
"Content-Description");
315 if (convertNonMimeBinaries) {
316 h_ead.replace(TQRegExp(
"MIME-Version: .*\\n"),
"");
317 h_ead.replace(TQRegExp(
"Content-Type: .*\\n"),
"");
318 h_ead.replace(TQRegExp(
"Content-Transfer-Encoding: .*\\n"),
"");
319 h_ead+=
"MIME-Version: 1.0\n";
320 h_ead+=contentType(
true)->as7BitString()+
"\n";
321 h_ead+=contentTransferEncoding(
true)->as7BitString()+
"\n";
330 if(!b_ody.isEmpty()) {
331 Headers::CTEncoding *enc=contentTransferEncoding();
333 if(enc->needToEncode()) {
334 if(enc->cte()==Headers::CEquPr) {
335 TQByteArray temp(b_ody.length());
336 memcpy(temp.data(), b_ody.data(), b_ody.length());
337 e+=KCodecs::quotedPrintableEncode(temp,
false);
339 e+=KCodecs::base64Encode(b_ody,
true);
346 else if(c_ontents && !c_ontents->isEmpty()) {
347 Headers::ContentType *ct=contentType();
348 TQCString boundary=
"\n--"+ct->boundary();
351 for(
Content *c=c_ontents->first(); c; c=c_ontents->next()) {
353 e+=c->encodedContent(
false);
366 TQByteArray Content::decodedContent()
368 TQByteArray temp, ret;
369 Headers::CTEncoding *ec=contentTransferEncoding();
370 bool removeTrailingNewline=
false;
371 int size=ec->cte()==Headers::CEbinary ? b_ody.size() : b_ody.length();
377 memcpy(temp.data(), b_ody.data(), size);
381 removeTrailingNewline=
true;
384 case Headers::CEbase64 :
385 KCodecs::base64Decode(temp, ret);
387 case Headers::CEquPr :
388 ret = KCodecs::quotedPrintableDecode(b_ody);
389 ret.resize(ret.size()-1);
390 removeTrailingNewline=
true;
392 case Headers::CEuuenc :
393 KCodecs::uudecode(temp, ret);
395 case Headers::CEbinary :
397 removeTrailingNewline=
false;
401 removeTrailingNewline=
true;
405 if (removeTrailingNewline && (ret.size()>0) && (ret[ret.size()-1] ==
'\n'))
406 ret.resize(ret.size()-1);
412 void Content::decodedText(TQString &s,
bool trimText,
413 bool removeTrailingNewlines)
419 TQTextCodec *codec=TDEGlobal::charsets()->codecForName(contentType()->charset(),ok);
421 s=codec->toUnicode(b_ody.data(), b_ody.length());
423 if (trimText && removeTrailingNewlines) {
425 for (i=s.length()-1; i>=0; i--)
430 if (s.right(1)==
"\n")
431 s.truncate(s.length()-1);
436 void Content::decodedText(TQStringList &l,
bool trimText,
437 bool removeTrailingNewlines)
445 TQTextCodec *codec=TDEGlobal::charsets()->codecForName(contentType()->charset(),ok);
447 unicode=codec->toUnicode(b_ody.data(), b_ody.length());
449 if (trimText && removeTrailingNewlines) {
451 for (i=unicode.length()-1; i>=0; i--)
452 if (!unicode[i].isSpace())
454 unicode.truncate(i+1);
456 if (unicode.right(1)==
"\n")
457 unicode.truncate(unicode.length()-1);
460 l=TQStringList::split(
'\n', unicode,
true);
464 void Content::fromUnicodeString(
const TQString &s)
467 TQTextCodec *codec=TDEGlobal::charsets()->codecForName(contentType()->charset(),ok);
470 codec=TDEGlobal::locale()->codecForEncoding();
471 TQCString chset=TDEGlobal::locale()->encoding();
472 contentType()->setCharset(chset);
475 b_ody=codec->fromUnicode(s);
476 contentTransferEncoding()->setDecoded(
true);
480 Content* Content::textContent()
485 if(contentType()->isText())
488 for(
Content *c=c_ontents->first(); c; c=c_ontents->next())
489 if( (ret=c->textContent())!=0 )
496 void Content::attachments(Content::List *dst,
bool incAlternatives)
498 dst->setAutoDelete(
false);
503 for(
Content *c=c_ontents->first(); c; c=c_ontents->next()) {
504 if( !incAlternatives && c->contentType()->category()==Headers::CCalternativePart)
507 c->attachments(dst, incAlternatives);
511 if(type()!=ATmimeContent) {
514 dst->removeRef(text);
519 void Content::addContent(
Content *c,
bool prepend)
522 c_ontents=
new List();
523 c_ontents->setAutoDelete(
true);
531 main->h_eaders=
new Headers::Base::List();
532 main->h_eaders->setAutoDelete(
true);
534 Headers::Base::List srcHdrs=(*h_eaders);
535 srcHdrs.setAutoDelete(
false);
540 idx=h_eaders->findRef(h);
543 main->h_eaders->append(h);
549 main->contentType()->setCategory(Headers::CCmixedPart);
555 main->b_ody=b_ody.copy();
556 c_ontents->append(main);
561 Headers::ContentType *ct=contentType();
562 ct->setMimeType(
"multipart/mixed");
563 ct->setBoundary(multiPartBoundary());
564 ct->setCategory(Headers::CCcontainer);
565 contentTransferEncoding()->clear();
570 c_ontents->insert(0, c);
572 c_ontents->append(c);
576 void Content::removeContent(
Content *c,
bool del)
583 c_ontents->removeRef(c);
585 idx=c_ontents->findRef(c);
586 c_ontents->take(idx);
590 if(c_ontents->count()==1) {
591 Content *main=c_ontents->first();
596 h_eaders=
new Headers::Base::List();
597 h_eaders->setAutoDelete(
true);
600 Headers::Base::List mainHdrs=(*(main->h_eaders));
601 mainHdrs.setAutoDelete(
false);
603 for(
Headers::Base *h=mainHdrs.first(); h; h=mainHdrs.next()) {
605 removeHeader(h->
type());
607 idx=main->h_eaders->findRef(h);
608 main->h_eaders->take(idx);
609 kdDebug(5003) <<
"Content::removeContent(Content *c, bool del) : mime-header moved: "
616 b_ody=main->b_ody.copy();
625 void Content::changeEncoding(Headers::contentEncoding e)
627 Headers::CTEncoding *enc=contentTransferEncoding();
635 if(e!=Headers::CEbase64) {
641 b_ody = KCodecs::base64Encode(decodedContent(),
true);
644 enc->setDecoded(
false);
650 void Content::toStream(TQTextStream &ts,
bool scrambleFromLines)
652 TQCString ret=encodedContent(
false);
654 if (scrambleFromLines)
655 ret.replace(TQRegExp(
"\\n\\nFrom "),
"\n\n>From ");
663 int pos1=-1, pos2=0, len=head.length()-1;
667 pos1 = head.find(
": ");
672 if (head[pos2]!=
'\n') {
674 pos2=head.find(
"\n", pos2+1);
675 if(pos2==-1 || pos2==len || ( head[pos2+1]!=
' ' && head[pos2+1]!=
'\t') )
682 if(pos2<0) pos2=len+1;
685 header =
new Headers::Generic(head.left(pos1-2),
this, head.mid(pos1, pos2-pos1));
687 header =
new Headers::Generic(head.left(pos1-2),
this, head.mid(pos1, pos2-pos1).replace(TQRegExp(
"\\s*\\n\\s*"),
" "));
689 head.remove(0,pos2+1);
707 for(h=h_eaders->first(); h; h=h_eaders->next())
708 if(h->
is(type))
return h;
711 TQCString raw=rawHeader(type);
714 if(strcasecmp(
"Message-Id", type)==0)
715 h=
new Headers::MessageID(
this, raw);
716 else if(strcasecmp(
"Subject", type)==0)
718 else if(strcasecmp(
"Date", type)==0)
720 else if(strcasecmp(
"From", type)==0)
721 h=
new Headers::From(
this, raw);
722 else if(strcasecmp(
"Organization", type)==0)
724 else if(strcasecmp(
"Reply-To", type)==0)
725 h=
new Headers::ReplyTo(
this, raw);
726 else if(strcasecmp(
"Mail-Copies-To", type)==0)
727 h=
new Headers::MailCopiesTo(
this, raw);
728 else if(strcasecmp(
"To", type)==0)
729 h=
new Headers::To(
this, raw);
730 else if(strcasecmp(
"CC", type)==0)
731 h=
new Headers::CC(
this, raw);
732 else if(strcasecmp(
"BCC", type)==0)
733 h=
new Headers::BCC(
this, raw);
734 else if(strcasecmp(
"Newsgroups", type)==0)
736 else if(strcasecmp(
"Followup-To", type)==0)
738 else if(strcasecmp(
"References", type)==0)
739 h=
new Headers::References(
this, raw);
740 else if(strcasecmp(
"Lines", type)==0)
742 else if(strcasecmp(
"Content-Type", type)==0)
743 h=
new Headers::ContentType(
this, raw);
744 else if(strcasecmp(
"Content-Transfer-Encoding", type)==0)
745 h=
new Headers::CTEncoding(
this, raw);
746 else if(strcasecmp(
"Content-Disposition", type)==0)
747 h=
new Headers::CDisposition(
this, raw);
748 else if(strcasecmp(
"Content-Description", type)==0)
749 h=
new Headers::CDescription(
this, raw);
754 h_eaders=
new Headers::Base::List();
755 h_eaders->setAutoDelete(
true);
769 removeHeader(h->
type());
771 h_eaders=
new Headers::Base::List();
772 h_eaders->setAutoDelete(
true);
778 bool Content::removeHeader(
const char *type)
781 for(
Headers::Base *h=h_eaders->first(); h; h=h_eaders->next())
783 return h_eaders->remove();
791 int ret=b_ody.length();
793 if(contentTransferEncoding()->cte()==Headers::CEbase64)
800 int Content::storageSize()
807 for(
Content *c=c_ontents->first(); c; c=c_ontents->next())
815 int Content::lineCount()
818 if(type()==ATmimeContent)
819 ret+=h_ead.contains(
'\n');
820 ret+=b_ody.contains(
'\n');
822 if(c_ontents && !c_ontents->isEmpty())
823 for(
Content *c=c_ontents->first(); c; c=c_ontents->next())
830 TQCString Content::rawHeader(
const char *name)
832 return extractHeader(h_ead, name);
836 bool Content::decodeText()
838 Headers::CTEncoding *enc=contentTransferEncoding();
840 if(!contentType()->isText())
846 case Headers::CEbase64 :
847 b_ody=KCodecs::base64Decode(b_ody);
850 case Headers::CEquPr :
851 b_ody=KCodecs::quotedPrintableDecode(b_ody);
853 case Headers::CEuuenc :
854 b_ody=KCodecs::uudecode(b_ody);
857 case Headers::CEbinary :
858 b_ody=TQCString(b_ody.data(), b_ody.size()+1);
864 enc->setDecoded(
true);
869 void Content::setDefaultCharset(
const TQCString &cs)
871 d_efaultCS = KMime::cachedCharset(cs);
873 if(c_ontents && !c_ontents->isEmpty())
874 for(
Content *c=c_ontents->first(); c; c=c_ontents->next())
875 c->setDefaultCharset(cs);
883 void Content::setForceDefaultCS(
bool b)
887 if(c_ontents && !c_ontents->isEmpty())
888 for(
Content *c=c_ontents->first(); c; c=c_ontents->next())
889 c->setForceDefaultCS(b);
This class encapsulates a mime-encoded content.
Helper-class: splits a multipart-message into single parts as described in RFC 2046.
Helper-class: tries to extract the data from a possibly uuencoded message.
Helper-class: tries to extract the data from a possibly yenc encoded message.