diff --git a/kmime/kmime_content.cpp b/kmime/kmime_content.cpp index ad9c58d57..cfd4248c3 100644 --- a/kmime/kmime_content.cpp +++ b/kmime/kmime_content.cpp @@ -1,912 +1,919 @@ /* kmime_content.cpp KMime, the KDE internet mail/usenet news message library. Copyright (c) 2001 the KMime authors. See file AUTHORS for details This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #include "kmime_content.h" #include "kmime_parsers.h" #include #include #include #include #include #include //Added by qt3to4: #include #include #include using namespace KMime; namespace KMime { Content::Content() : h_eaders(0), f_orceDefaultCS(false) { d_efaultCS = cachedCharset("ISO-8859-1"); } Content::Content(const Q3CString &h, const Q3CString &b) : h_eaders(0), f_orceDefaultCS(false) { d_efaultCS = cachedCharset("ISO-8859-1"); h_ead=h.copy(); b_ody=b.copy(); } Content::~Content() { qDeleteAll( c_ontents ); c_ontents.clear(); + qDeleteAll( *h_eaders ); + h_eaders->clear(); delete h_eaders; } void Content::setContent(Q3StrList *l) { //qDebug("Content::setContent(QStrList *l) : start"); h_ead.resize(0); b_ody.resize(0); //usage of textstreams is much faster than simply appending the strings QTextStream hts(h_ead, QIODevice::WriteOnly), bts(b_ody, QIODevice::WriteOnly); hts.setEncoding(QTextStream::Latin1); bts.setEncoding(QTextStream::Latin1); bool isHead=true; for(char *line=l->first(); line; line=l->next()) { if(isHead && line[0]=='\0') { isHead=false; continue; } if(isHead) hts << line << "\n"; else bts << line << "\n"; } //terminate strings hts << '\0'; bts << '\0'; //qDebug("Content::setContent(QStrList *l) : finished"); } void Content::setContent( const QByteArray &s ) { int pos = s.indexOf( "\n\n", 0 ); if(pos>-1) { h_ead=s.left(++pos); //header *must* end with "\n" !! b_ody=s.mid(pos+1, s.length()-pos-1); } else h_ead=s; } //parse the message, split multiple parts void Content::parse() { //qDebug("void Content::parse() : start"); + qDeleteAll( *h_eaders ); + h_eaders->clear(); delete h_eaders; h_eaders=0; // check this part has already been partioned into subparts. // if this is the case, we will not try to reparse the body // of this part. if ( b_ody.size() == 0 && !c_ontents.isEmpty() ) { // reparse all sub parts foreach ( Content *c, c_ontents ) c->parse(); return; } qDeleteAll( c_ontents ); c_ontents.clear(); Headers::ContentType *ct=contentType(); Q3CString tmp; Content *c; Headers::contentCategory cat; // just "text" as mimetype is suspicious, perhaps this article was // generated by broken software, better check for uuencoded binaries if (ct->mimeType()=="text") ct->setMimeType("invalid/invalid"); if(ct->isText()) return; //nothing to do if(ct->isMultipart()) { //this is a multipart message tmp=ct->boundary(); //get boundary-parameter if(!tmp.isEmpty()) { Parser::MultiPart mpp(b_ody, tmp); if(mpp.parse()) { //at least one part found if(ct->isSubtype("alternative")) //examine category for the sub-parts cat=Headers::CCalternativePart; else cat=Headers::CCmixedPart; //default to "mixed" QCStringList parts=mpp.parts(); QCStringList::Iterator it; for(it=parts.begin(); it!=parts.end(); ++it) { //create a new Content for every part c=new Content(); c->setContent(*it); c->parse(); c->contentType()->setCategory(cat); //set category of the sub-part c_ontents.append( c ); //qDebug("part:\n%s\n\n%s", c->h_ead.data(), c->b_ody.left(100).data()); } //the whole content is now split into single parts, so it's safe delete the message-body b_ody.resize(0); } else { //sh*t, the parsing failed so we have to treat the message as "text/plain" instead ct->setMimeType("text/plain"); ct->setCharset("US-ASCII"); } } } else if (ct->mimeType()=="invalid/invalid") { //non-mime body => check for uuencoded content Parser::UUEncoded uup(b_ody, rawHeader("Subject")); if(uup.parse()) { // yep, it is uuencoded if(uup.isPartial()) { // this seems to be only a part of the message so we treat it as "message/partial" ct->setMimeType("message/partial"); //ct->setId(uniqueString()); not needed yet ct->setPartialParams(uup.partialCount(), uup.partialNumber()); contentTransferEncoding()->setCte(Headers::CE7Bit); } else { //it's a complete message => treat as "multipart/mixed" //the whole content is now split into single parts, so it's safe to delete the message-body b_ody.resize(0); //binary parts for (unsigned int i=0;isetContent(tmp); addContent(c); } if ( !c_ontents.isEmpty() && c_ontents.first() ) { //readd the plain text before the uuencoded part c_ontents.first()->setContent("Content-Type: text/plain\nContent-Transfer-Encoding: 7Bit\n\n"+uup.textPart()); c_ontents.first()->contentType()->setMimeType("text/plain"); } } } else { Parser::YENCEncoded yenc(b_ody); if ( yenc.parse()) { /* If it is partial, just assume there is exactly one decoded part, * and make this that part */ if (yenc.isPartial()) { ct->setMimeType("message/partial"); //ct->setId(uniqueString()); not needed yet ct->setPartialParams(yenc.partialCount(), yenc.partialNumber()); contentTransferEncoding()->setCte(Headers::CEbinary); } else { //it's a complete message => treat as "multipart/mixed" //the whole content is now split into single parts, so it's safe to delete the message-body b_ody.resize(0); //binary parts for (int i=0;isetContent(tmp); // the bodies of yenc message parts are binary data, not null-terminated strings: QByteArray body = yenc.binaryParts()[i]; Q3CString body_string(body.size()); memcpy(body_string.data(), body.data(), body.size()); c->setBody(body_string); addContent(c); } if( !c_ontents.isEmpty() && c_ontents.first() ) { //readd the plain text before the uuencoded part c_ontents.first()->setContent("Content-Type: text/plain\nContent-Transfer-Encoding: 7Bit\n\n"+yenc.textPart()); c_ontents.first()->contentType()->setMimeType("text/plain"); } } } else { //no, this doesn't look like uuencoded stuff => we treat it as "text/plain" ct->setMimeType("text/plain"); } } } //qDebug("void Content::parse() : finished"); } void Content::assemble() { Q3CString newHead=""; //Content-Type newHead+=contentType()->as7BitString()+"\n"; //Content-Transfer-Encoding newHead+=contentTransferEncoding()->as7BitString()+"\n"; //Content-Description Headers::Base *h=contentDescription(false); if(h) newHead+=h->as7BitString()+"\n"; //Content-Disposition h=contentDisposition(false); if(h) newHead+=h->as7BitString()+"\n"; h_ead=newHead; } void Content::clear() { + qDeleteAll( *h_eaders ); + h_eaders->clear(); delete h_eaders; h_eaders=0; qDeleteAll( c_ontents ); c_ontents.clear(); h_ead.resize(0); b_ody.resize(0); } Q3CString Content::encodedContent(bool useCrLf) { Q3CString e; // hack to convert articles with uuencoded or yencoded binaries into // proper mime-compliant articles if ( !c_ontents.isEmpty() ) { bool convertNonMimeBinaries=false; // reencode non-mime binaries... foreach ( Content *c, c_ontents ) { if ((c->contentTransferEncoding(true)->cte()==Headers::CEuuenc) || (c->contentTransferEncoding(true)->cte()==Headers::CEbinary)) { convertNonMimeBinaries=true; c->b_ody = KCodecs::base64Encode(c->decodedContent(), true); c->b_ody.append("\n"); c->contentTransferEncoding(true)->setCte(Headers::CEbase64); c->contentTransferEncoding(true)->setDecoded(false); c->removeHeader("Content-Description"); c->assemble(); } } // add proper mime headers... if (convertNonMimeBinaries) { int beg = 0, end = 0; beg = h_ead.indexOf( "MIME-Version: " ); if ( beg >= 0 ) end = h_ead.indexOf( '\n', beg ); if ( beg >= 0 && end > beg ) h_ead.remove( beg, end - beg ); beg = h_ead.indexOf( "Content-Type: " ); if ( beg >= 0 ) end = h_ead.indexOf( '\n', beg ); if ( beg >= 0 && end > beg ) h_ead.remove( beg, end - beg ); beg = h_ead.indexOf( "Content-Transfer-Encoding: " ); if ( beg >= 0 ) end = h_ead.indexOf( '\n', beg ); if ( beg >= 0 && end > beg ) h_ead.remove( beg, end - beg ); h_ead+="MIME-Version: 1.0\n"; h_ead+=contentType(true)->as7BitString()+"\n"; h_ead+=contentTransferEncoding(true)->as7BitString()+"\n"; } } //head e=h_ead.copy(); e+="\n"; //body if(!b_ody.isEmpty()) { //this message contains only one part Headers::CTEncoding *enc=contentTransferEncoding(); if(enc->needToEncode()) { if(enc->cte()==Headers::CEquPr) { QByteArray temp(b_ody.length()); memcpy(temp.data(), b_ody.data(), b_ody.length()); e+=KCodecs::quotedPrintableEncode(temp, false); } else { e+=KCodecs::base64Encode(b_ody, true); e+="\n"; } } else e+=b_ody; } else if( !c_ontents.isEmpty() ) { //this is a multipart message Headers::ContentType *ct=contentType(); Q3CString boundary="--"+ct->boundary(); //add all (encoded) contents separated by boundaries foreach ( Content *c, c_ontents ) { e+=boundary+"\n"; e+=c->encodedContent(false); // don't convert LFs here, we do that later!!!!! } //finally append the closing boundary e+=boundary+"--\n"; }; if(useCrLf) return LFtoCRLF(e); else return e; } QByteArray Content::decodedContent() { QByteArray temp, ret; Headers::CTEncoding *ec=contentTransferEncoding(); bool removeTrailingNewline=false; int size=ec->cte()==Headers::CEbinary ? b_ody.size() : b_ody.length(); if (size==0) return ret; temp.resize(size); memcpy(temp.data(), b_ody.data(), size); if(ec->decoded()) { ret = temp; removeTrailingNewline=true; } else { switch(ec->cte()) { case Headers::CEbase64 : KCodecs::base64Decode(temp, ret); break; case Headers::CEquPr : ret = KCodecs::quotedPrintableDecode(b_ody); ret.resize(ret.size()-1); // remove null-char removeTrailingNewline=true; break; case Headers::CEuuenc : KCodecs::uudecode(temp, ret); break; case Headers::CEbinary : ret = temp; removeTrailingNewline=false; default : ret = temp; removeTrailingNewline=true; } } if (removeTrailingNewline && (ret.size()>0) && (ret[ret.size()-1] == '\n')) ret.resize(ret.size()-1); return ret; } void Content::decodedText(QString &s, bool trimText, bool removeTrailingNewlines) { if(!decodeText()) //this is not a text content !! return; bool ok=true; QTextCodec *codec=KGlobal::charsets()->codecForName(contentType()->charset(),ok); s=codec->toUnicode(b_ody.data(), b_ody.length()); if (trimText && removeTrailingNewlines) { int i; for (i=s.length()-1; i>=0; i--) if (!s[i].isSpace()) break; s.truncate(i+1); } else { if (s.right(1)=="\n") s.truncate(s.length()-1); // remove trailing new-line } } void Content::decodedText(QStringList &l, bool trimText, bool removeTrailingNewlines) { if(!decodeText()) //this is not a text content !! return; QString unicode; bool ok=true; QTextCodec *codec=KGlobal::charsets()->codecForName(contentType()->charset(),ok); unicode=codec->toUnicode(b_ody.data(), b_ody.length()); if (trimText && removeTrailingNewlines) { int i; for (i=unicode.length()-1; i>=0; i--) if (!unicode[i].isSpace()) break; unicode.truncate(i+1); } else { if (unicode.right(1)=="\n") unicode.truncate(unicode.length()-1); // remove trailing new-line } l=QStringList::split('\n', unicode, true); //split the string at linebreaks } void Content::fromUnicodeString(const QString &s) { bool ok=true; QTextCodec *codec=KGlobal::charsets()->codecForName(contentType()->charset(),ok); if(!ok) { // no suitable codec found => try local settings and hope the best ;-) codec=KGlobal::locale()->codecForEncoding(); Q3CString chset=KGlobal::locale()->encoding(); contentType()->setCharset(chset); } b_ody=codec->fromUnicode(s); contentTransferEncoding()->setDecoded(true); //text is always decoded } Content* Content::textContent() { Content *ret=0; //return the first content with mimetype=text/* if(contentType()->isText()) ret=this; else foreach ( Content *c, c_ontents ) if( (ret=c->textContent())!=0 ) break; return ret; } void Content::attachments( Content::List &dst, bool incAlternatives ) { if ( c_ontents.isEmpty() ) dst.append(this); else { foreach ( Content *c, c_ontents ) { if( !incAlternatives && c->contentType()->category()==Headers::CCalternativePart) continue; else c->attachments(dst, incAlternatives); } } if(type()!=ATmimeContent) { // this is the toplevel article Content *text=textContent(); if(text) dst.removeAll( text ); } } void Content::addContent(Content *c, bool prepend) { if ( c_ontents.isEmpty() ) { // this message is not multipart yet // first we convert the body to a content Content *main=new Content(); //the Mime-Headers are needed, so we move them to the new content if(h_eaders) { main->h_eaders=new Headers::Base::List(); - main->h_eaders->setAutoDelete(true); - - Headers::Base::List srcHdrs=(*h_eaders); - srcHdrs.setAutoDelete(false); - int idx=0; - for(Headers::Base *h=srcHdrs.first(); h; h=srcHdrs.next()) { - if(h->isMimeHeader()) { - //remove from this content - idx=h_eaders->findRef(h); - h_eaders->take(idx); - //append to new content - main->h_eaders->append(h); + + for ( Headers::Base::List::iterator it = h_eaders->begin(); + it != h_eaders->end(); ) { + if ( (*it)->isMimeHeader() ) { + // append to new content + main->h_eaders->append( *it ); + // and remove from this content + h_eaders->erase( it ); } + else + ++it; } } //"main" is now part of a multipart/mixed message main->contentType()->setCategory(Headers::CCmixedPart); //the head of "main" is empty, so we assemble it main->assemble(); //now we can copy the body and append the new content; main->b_ody=b_ody.copy(); c_ontents.append( main ); b_ody.resize(0); //not longer needed //finally we have to convert this article to "multipart/mixed" Headers::ContentType *ct=contentType(); ct->setMimeType("multipart/mixed"); ct->setBoundary(multiPartBoundary()); ct->setCategory(Headers::CCcontainer); contentTransferEncoding()->clear(); // 7Bit, decoded } //here we actually add the content if(prepend) c_ontents.insert( 0, c ); else c_ontents.append( c ); } void Content::removeContent(Content *c, bool del) { if( c_ontents.isEmpty() ) // what the .. return; - int idx=0; c_ontents.removeAll( c ); if(del) delete c; //only one content left => turn this message in a single-part if ( c_ontents.count() == 1 ) { Content *main = c_ontents.first(); //first we have to move the mime-headers if(main->h_eaders) { if(!h_eaders) { h_eaders=new Headers::Base::List(); - h_eaders->setAutoDelete(true); } - Headers::Base::List mainHdrs=(*(main->h_eaders)); - mainHdrs.setAutoDelete(false); - - for(Headers::Base *h=mainHdrs.first(); h; h=mainHdrs.next()) { - if(h->isMimeHeader()) { - removeHeader(h->type()); //remove the old header first - h_eaders->append(h); //now append the new one - idx=main->h_eaders->findRef(h); - main->h_eaders->take(idx); //remove from the old content + for ( Headers::Base::List::iterator it = main->h_eaders->begin(); + it != main->h_eaders->end(); ) { + if ( (*it)->isMimeHeader() ) { kdDebug(5003) << "Content::removeContent(Content *c, bool del) : mime-header moved: " - << h->as7BitString() << endl; + << (*it)->as7BitString() << endl; + // first remove the old header + removeHeader( (*it)->type() ); + // then append to new content + h_eaders->append( *it ); + // and finally remove from this content + main->h_eaders->erase( it ); } + else + ++it; } } //now we can copy the body b_ody=main->b_ody.copy(); //finally we can delete the content list qDeleteAll( c_ontents ); c_ontents.clear(); } } void Content::changeEncoding(Headers::contentEncoding e) { Headers::CTEncoding *enc=contentTransferEncoding(); if(enc->cte()==e) //nothing to do return; if(decodeText()) enc->setCte(e); // text is not encoded until it's sent or saved so we just set the new encoding else { // this content contains non textual data, that has to be re-encoded if(e!=Headers::CEbase64) { //kdWarning(5003) << "Content::changeEncoding() : non textual data and encoding != base64 - this should not happen\n => forcing base64" << endl; e=Headers::CEbase64; } if(enc->cte()!=e) { // ok, we reencode the content using base64 b_ody = KCodecs::base64Encode(decodedContent(), true); b_ody.append("\n"); enc->setCte(e); //set encoding enc->setDecoded(false); } } } void Content::toStream(QTextStream &ts, bool scrambleFromLines) { Q3CString ret=encodedContent(false); if (scrambleFromLines) ret.replace( "\n\nFrom ", "\n\n>From "); ts << ret; } Headers::Generic* Content::getNextHeader(Q3CString &head) { int pos1=-1, pos2=0, len=head.length()-1; bool folded(false); Headers::Generic *header=0; pos1 = head.find(": "); if (pos1>-1) { //there is another header pos2=pos1+=2; //skip the name if (head[pos2]!='\n') { // check if the header is not empty while(1) { pos2=head.find("\n", pos2+1); if(pos2==-1 || pos2==len || ( head[pos2+1]!=' ' && head[pos2+1]!='\t') ) //break if we reach the end of the string, honor folded lines break; else folded = true; } } if(pos2<0) pos2=len+1; //take the rest of the string if (!folded) header = new Headers::Generic(head.left(pos1-2), this, head.mid(pos1, pos2-pos1)); else { QByteArray hdrValue = head.mid( pos1, pos2 - pos1 ); // unfold header int beg = 0, mid = 0, end = 0; while ( (mid = hdrValue.indexOf( '\n' )) >= 0 ) { beg = end = mid; while ( beg > 0 ) { if ( !QChar( hdrValue[beg] ).isSpace() ) break; --beg; } while ( end < hdrValue.length() - 1 ) { if ( !QChar( hdrValue[end] ).isSpace() ) break; ++end; } hdrValue.remove( beg, end - beg ); } header = new Headers::Generic( head.left( pos1 - 2 ), this, hdrValue ); } head.remove(0,pos2+1); } else { head = ""; } return header; } Headers::Base* Content::getHeaderByType(const char *type) { if(!type) return 0; - Headers::Base *h=0; //first we check if the requested header is already cached if(h_eaders) - for(h=h_eaders->first(); h; h=h_eaders->next()) - if(h->is(type)) return h; //found + foreach ( Headers::Base *h, *h_eaders ) + if ( h->is( type ) ) + return h; //found //now we look for it in the article head + Headers::Base *h = 0; Q3CString raw=rawHeader(type); if(!raw.isEmpty()) { //ok, we found it //choose a suitable header class if(strcasecmp("Message-Id", type)==0) h=new Headers::MessageID(this, raw); else if(strcasecmp("Subject", type)==0) h=new Headers::Subject(this, raw); else if(strcasecmp("Date", type)==0) h=new Headers::Date(this, raw); else if(strcasecmp("From", type)==0) h=new Headers::From(this, raw); else if(strcasecmp("Organization", type)==0) h=new Headers::Organization(this, raw); else if(strcasecmp("Reply-To", type)==0) h=new Headers::ReplyTo(this, raw); else if(strcasecmp("Mail-Copies-To", type)==0) h=new Headers::MailCopiesTo(this, raw); else if(strcasecmp("To", type)==0) h=new Headers::To(this, raw); else if(strcasecmp("CC", type)==0) h=new Headers::CC(this, raw); else if(strcasecmp("BCC", type)==0) h=new Headers::BCC(this, raw); else if(strcasecmp("Newsgroups", type)==0) h=new Headers::Newsgroups(this, raw); else if(strcasecmp("Followup-To", type)==0) h=new Headers::FollowUpTo(this, raw); else if(strcasecmp("References", type)==0) h=new Headers::References(this, raw); else if(strcasecmp("Lines", type)==0) h=new Headers::Lines(this, raw); else if(strcasecmp("Content-Type", type)==0) h=new Headers::ContentType(this, raw); else if(strcasecmp("Content-Transfer-Encoding", type)==0) h=new Headers::CTEncoding(this, raw); else if(strcasecmp("Content-Disposition", type)==0) h=new Headers::CDisposition(this, raw); else if(strcasecmp("Content-Description", type)==0) h=new Headers::CDescription(this, raw); else h=new Headers::Generic(type, this, raw); if(!h_eaders) { h_eaders=new Headers::Base::List(); - h_eaders->setAutoDelete(true); } h_eaders->append(h); //add to cache return h; } else return 0; //header not found } void Content::setHeader(Headers::Base *h) { if(!h) return; removeHeader(h->type()); if(!h_eaders) { h_eaders=new Headers::Base::List(); - h_eaders->setAutoDelete(true); } h_eaders->append(h); } bool Content::removeHeader(const char *type) { if(h_eaders) - for(Headers::Base *h=h_eaders->first(); h; h=h_eaders->next()) - if(h->is(type)) - return h_eaders->remove(); + for ( Headers::Base::List::iterator it = h_eaders->begin(); + it != h_eaders->end(); ++it ) + if ( (*it)->is(type) ) { + delete (*it); + h_eaders->erase( it ); + return true; + } return false; } int Content::size() { int ret=b_ody.length(); if(contentTransferEncoding()->cte()==Headers::CEbase64) return (ret*3/4); //base64 => 6 bit per byte return ret; } int Content::storageSize() { int s=h_ead.size(); if ( c_ontents.isEmpty() ) s+=b_ody.size(); else { foreach ( Content *c, c_ontents ) s+=c->storageSize(); } return s; } int Content::lineCount() { int ret=0; if(type()==ATmimeContent) ret+=h_ead.count('\n'); ret+=b_ody.count('\n'); foreach ( Content *c, c_ontents ) ret+=c->lineCount(); return ret; } Q3CString Content::rawHeader(const char *name) { return extractHeader(h_ead, name); } bool Content::decodeText() { Headers::CTEncoding *enc=contentTransferEncoding(); if(!contentType()->isText()) return false; //non textual data cannot be decoded here => use decodedContent() instead if(enc->decoded()) return true; //nothing to do switch(enc->cte()) { case Headers::CEbase64 : b_ody=KCodecs::base64Decode(b_ody); b_ody.append("\n"); break; case Headers::CEquPr : b_ody=KCodecs::quotedPrintableDecode(b_ody); break; case Headers::CEuuenc : b_ody=KCodecs::uudecode(b_ody); b_ody.append("\n"); break; case Headers::CEbinary : b_ody=Q3CString(b_ody.data(), b_ody.size()+1); b_ody.append("\n"); default : break; } enc->setDecoded(true); return true; } void Content::setDefaultCharset( const QByteArray &cs ) { d_efaultCS = KMime::cachedCharset(cs); foreach ( Content *c, c_ontents ) c->setDefaultCharset(cs); // reparse the part and its sub-parts in order // to clear cached header values parse(); } void Content::setForceDefaultCS(bool b) { f_orceDefaultCS=b; foreach ( Content *c, c_ontents ) c->setForceDefaultCS(b); // reparse the part and its sub-parts in order // to clear cached header values parse(); } } // namespace KMime diff --git a/kmime/kmime_content.h b/kmime/kmime_content.h index 9238e846f..747ce9653 100644 --- a/kmime/kmime_content.h +++ b/kmime/kmime_content.h @@ -1,173 +1,172 @@ /* kmime_content.h KMime, the KDE internet mail/usenet news message library. Copyright (c) 2001 the KMime authors. See file AUTHORS for details This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #ifndef __KMIME_CONTENT_H__ #define __KMIME_CONTENT_H__ //forward declarations #if 0 class KMime::Headers::Base; class KMime::Headers::Generic; class KMime::Headers::ContentType; class KMime::Headers::CTEncoding; class KMime::Headers::CDisposition; class KMime::Headers::List; #endif #include "kmime_util.h" #include "kmime_headers.h" #include //Added by qt3to4: #include #include namespace KMime { /** Base class for messages in mime format It contains all the enums, static functions and parser-classes, that are needed for mime handling */ class Base { public: //enums enum articleType { ATmimeContent, ATremote, ATlocal }; }; /** This class encapsulates a mime-encoded content. It parses the given data and creates a tree-like structure, that represents the structure of the message */ class KDE_EXPORT Content : public Base { public: typedef QList List; Content(); Content(const Q3CString &h, const Q3CString &b); virtual ~Content(); //type virtual articleType type() { return ATmimeContent; } //content handling bool hasContent() { return ( !h_ead.isEmpty() && (!b_ody.isEmpty() || !c_ontents.isEmpty()) ); } void setContent(Q3StrList *l); void setContent( const QByteArray &s ); virtual void parse(); virtual void assemble(); virtual void clear(); //header access Q3CString head() { return h_ead; } // extracts and removes the next header from head. The caller has to delete the returned header; Headers::Generic* getNextHeader(Q3CString &head); virtual Headers::Base* getHeaderByType(const char *type); virtual void setHeader(Headers::Base *h); virtual bool removeHeader(const char *type); bool hasHeader(const char *type) { return (getHeaderByType(type)!=0); } Headers::ContentType* contentType(bool create=true) { Headers::ContentType *p=0; return getHeaderInstance(p, create); } Headers::CTEncoding* contentTransferEncoding(bool create=true) { Headers::CTEncoding *p=0; return getHeaderInstance(p, create); } Headers::CDisposition* contentDisposition(bool create=true) { Headers::CDisposition *p=0; return getHeaderInstance(p, create); } Headers::CDescription* contentDescription(bool create=true) { Headers::CDescription *p=0; return getHeaderInstance(p, create); } //content access int size(); int storageSize(); int lineCount(); Q3CString body() { return b_ody; } void setBody( const Q3CString & str ) { b_ody = str; } Q3CString encodedContent(bool useCrLf=false); QByteArray decodedContent(); void decodedText(QString &s, bool trimText=false, bool removeTrailingNewlines=false); void decodedText(QStringList &s, bool trimText=false, bool removeTrailingNewlines=false); void fromUnicodeString(const QString &s); Content* textContent(); void attachments(List &dst, bool incAlternatives=false); void addContent(Content *c, bool prepend=false); void removeContent(Content *c, bool del=false); void changeEncoding(Headers::contentEncoding e); //saves the encoded content to the given textstream // scrambleFromLines: replace "\nFrom " with "\n>From ", this is // needed to avoid problem with mbox-files void toStream(QTextStream &ts, bool scrambleFromLines=false); // this charset is used for all headers and the body // if the charset is not declared explictly QByteArray defaultCharset() const { return QByteArray( d_efaultCS ); } void setDefaultCharset( const QByteArray &cs ); // use the default charset even if a different charset is // declared in the article bool forceDefaultCS() { return f_orceDefaultCS; } // enables/disables the force mode, housekeeping. // works correctly only when the article is completely empty or // completely loaded virtual void setForceDefaultCS(bool b); protected: Q3CString rawHeader(const char *name); bool decodeText(); template T* getHeaderInstance(T *ptr, bool create); Q3CString h_ead, b_ody; List c_ontents; Headers::Base::List *h_eaders; const char *d_efaultCS; bool f_orceDefaultCS; }; // some compilers (for instance Compaq C++) need template inline functions // here rather than in the *.cpp file template T* Content::getHeaderInstance(T *ptr, bool create) { T dummy; //needed to access virtual member T::type() ptr=static_cast (getHeaderByType(dummy.type())); if(!ptr && create) { //no such header found, but we need one => create it ptr=new T(this); if(!(h_eaders)) { h_eaders=new Headers::Base::List(); - h_eaders->setAutoDelete(true); } h_eaders->append(ptr); } return ptr; } } // namespace KMime #endif // __KMIME_CONTENT_H__ diff --git a/kmime/kmime_headers.cpp b/kmime/kmime_headers.cpp index 500275afb..30b502586 100644 --- a/kmime/kmime_headers.cpp +++ b/kmime/kmime_headers.cpp @@ -1,1595 +1,1593 @@ /* kmime_headers.cpp KMime, the KDE internet mail/usenet news message library. Copyright (c) 2001-2002 the KMime authors. See file AUTHORS for details This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #include "kmime_headers.h" #include "kmime_util.h" #include "kmime_content.h" #include "kmime_codecs.h" #include "kmime_header_parsing.h" #include "kmime_warning.h" #include #include #include #include -//Added by qt3to4: -#include #include #include #include #include using namespace KMime; using namespace KMime::Headers; using namespace KMime::Types; using namespace KMime::HeaderParsing; namespace KMime { namespace Headers { //--------------------------------------- Q3CString Base::rfc2047Charset() { if( (e_ncCS==0) || forceCS() ) return defaultCS(); else return Q3CString(e_ncCS); } void Base::setRFC2047Charset(const Q3CString &cs) { e_ncCS=cachedCharset(cs); } bool Base::forceCS() { return ( p_arent!=0 ? p_arent->forceDefaultCS() : false ); } QByteArray Base::defaultCS() { return ( p_arent!=0 ? p_arent->defaultCharset() : Latin1 ); } //-------------------------------------- namespace Generics { //------------------------------ void GUnstructured::from7BitString( const Q3CString & str ) { d_ecoded = decodeRFC2047String( str, &e_ncCS, defaultCS(), forceCS() ); } Q3CString GUnstructured::as7BitString( bool withHeaderType ) { Q3CString result; if ( withHeaderType ) result = typeIntro(); result += encodeRFC2047String( d_ecoded, e_ncCS ) ; return result; } void GUnstructured::fromUnicodeString( const QString & str, const Q3CString & suggestedCharset ) { d_ecoded = str; e_ncCS = cachedCharset( suggestedCharset ); } QString GUnstructured::asUnicodeString() { return d_ecoded; } //------------------------------ //------------------------------ //------------------------------ //------------------------------ //------------------------------ //------------------------------ bool MailboxList::parse( const char* & scursor, const char * const send, bool isCRLF ) { // examples: // from := "From:" mailbox-list CRLF // sender := "Sender:" mailbox CRLF // parse an address-list: QList
maybeAddressList; if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) return false; mMailboxList.clear(); // extract the mailboxes and complain if there are groups: QList
::Iterator it; for ( it = maybeAddressList.begin(); it != maybeAddressList.end() ; ++it ) { if ( !(*it).displayName.isEmpty() ) { KMIME_WARN << "mailbox groups in header disallowing them! Name: \"" << (*it).displayName << "\"" << endl; } mMailboxList += (*it).mailboxList; } return true; } //------------------------------ //------------------------------ bool SingleMailbox::parse( const char* & scursor, const char * const send, bool isCRLF ) { if ( !MailboxList::parse( scursor, send, isCRLF ) ) return false; if ( mMailboxList.count() > 1 ) { KMIME_WARN << "multiple mailboxes in header allowing only a single one!" << endl; } return true; } //------------------------------ //------------------------------ bool AddressList::parse( const char* & scursor, const char * const send, bool isCRLF ) { QList
maybeAddressList; if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) return false; mAddressList = maybeAddressList; return true; } //------------------------------ //------------------------------ bool GToken::parse( const char* & scursor, const char * const send, bool isCRLF ) { eatCFWS( scursor, send, isCRLF ); // must not be empty: if ( scursor == send ) return false; QPair maybeToken; if ( !parseToken( scursor, send, maybeToken, false /* no 8bit chars */ ) ) return false; mToken = Q3CString( maybeToken.first, maybeToken.second ); // complain if trailing garbage is found: eatCFWS( scursor, send, isCRLF ); if ( scursor != send ) { KMIME_WARN << "trailing garbage after token in header allowing " "only a single token!" << endl; } return true; } //------------------------------ //------------------------------ bool GPhraseList::parse( const char* & scursor, const char * const send, bool isCRLF ) { mPhraseList.clear(); while ( scursor != send ) { eatCFWS( scursor, send, isCRLF ); // empty entry ending the list: OK. if ( scursor == send ) return true; // empty entry: ignore. if ( *scursor != ',' ) { scursor++; continue; } QString maybePhrase; if ( !parsePhrase( scursor, send, maybePhrase, isCRLF ) ) return false; mPhraseList.append( maybePhrase ); eatCFWS( scursor, send, isCRLF ); // non-empty entry ending the list: OK. if ( scursor == send ) return true; // comma separating the phrases: eat. if ( *scursor != ',' ) scursor++; } return true; } //------------------------------ //------------------------------ bool GDotAtom::parse( const char* & scursor, const char * const send, bool isCRLF ) { QString maybeDotAtom; if ( !parseDotAtom( scursor, send, maybeDotAtom, isCRLF ) ) return false; mDotAtom = maybeDotAtom; eatCFWS( scursor, send, isCRLF ); if ( scursor != send ) { KMIME_WARN << "trailing garbage after dot-atom in header allowing " "only a single dot-atom!" << endl; } return true; } //------------------------------ //------------------------------ //------------------------------ //------------------------------ bool GContentType::parse( const char* & scursor, const char * const send, bool isCRLF ) { // content-type: type "/" subtype *(";" parameter) mMimeType = 0; mMimeSubType = 0; mParameterHash.clear(); eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) { // empty header return false; } // // type // QPair maybeMimeType; if ( !parseToken( scursor, send, maybeMimeType, false /* no 8Bit */ ) ) return false; mMimeType = Q3CString( maybeMimeType.first, maybeMimeType.second ).lower(); // // subtype // eatCFWS( scursor, send, isCRLF ); if ( scursor == send || *scursor != '/' ) return false; scursor++; eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) return false; QPair maybeSubType; if ( !parseToken( scursor, send, maybeSubType, false /* no 8bit */ ) ) return false; mMimeSubType = Q3CString( maybeSubType.first, maybeSubType.second ).lower(); // // parameter list // eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) return true; // no parameters if ( *scursor != ';' ) return false; scursor++; if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) ) return false; return true; } //------------------------------ //------------------------------ bool GCISTokenWithParameterList::parse( const char* & scursor, const char * const send, bool isCRLF ) { mToken = 0; mParameterHash.clear(); // // token // eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) return false; QPair maybeToken; if ( !parseToken( scursor, send, maybeToken, false /* no 8Bit */ ) ) return false; mToken = Q3CString( maybeToken.first, maybeToken.second ).lower(); // // parameter list // eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) return true; // no parameters if ( *scursor != ';' ) return false; scursor++; if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) ) return false; return true; } //------------------------------ //------------------------------ bool GIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) { // msg-id := "<" id-left "@" id-right ">" // id-left := dot-atom-text / no-fold-quote / local-part // id-right := dot-atom-text / no-fold-literal / domain // // equivalent to: // msg-id := angle-addr mMsgIdList.clear(); while ( scursor != send ) { eatCFWS( scursor, send, isCRLF ); // empty entry ending the list: OK. if ( scursor == send ) return true; // empty entry: ignore. if ( *scursor == ',' ) { scursor++; continue; } AddrSpec maybeMsgId; if ( !parseAngleAddr( scursor, send, maybeMsgId, isCRLF ) ) return false; mMsgIdList.append( maybeMsgId ); eatCFWS( scursor, send, isCRLF ); // header end ending the list: OK. if ( scursor == send ) return true; // regular item separator: eat it. if ( *scursor == ',' ) scursor++; } return true; } //------------------------------ //------------------------------ bool GSingleIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) { if ( !GIdent::parse( scursor, send, isCRLF ) ) return false; if ( mMsgIdList.count() > 1 ) { KMIME_WARN << "more than one msg-id in header " "allowing only a single one!" << endl; } return true; } //------------------------------ } // namespace Generics //------------------------------ bool ReturnPath::parse( const char* & scursor, const char * const send, bool isCRLF ) { eatCFWS( scursor, send, isCRLF ); if ( scursor == send ) return false; const char * oldscursor = scursor; Mailbox maybeMailbox; if ( !parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) { // mailbox parsing failed, but check for empty brackets: scursor = oldscursor; if ( *scursor != '<' ) return false; scursor++; eatCFWS( scursor, send, isCRLF ); if ( scursor == send || *scursor != '>' ) return false; scursor++; // prepare a Null mailbox: AddrSpec emptyAddrSpec; maybeMailbox.displayName.clear(); maybeMailbox.addrSpec = emptyAddrSpec; } else // check that there was no display-name: if ( !maybeMailbox.displayName.isEmpty() ) { KMIME_WARN << "display-name \"" << maybeMailbox.displayName << "\" in Return-Path!" << endl; } // see if that was all: eatCFWS( scursor, send, isCRLF ); // and warn if it wasn't: if ( scursor != send ) { KMIME_WARN << "trailing garbage after angle-addr in Return-Path!" << endl; } return true; } //------------------------------ //------------------------------------ void Generic::setType(const char *type) { if(t_ype) delete[] t_ype; if(type) { t_ype=new char[strlen(type)+1]; strcpy(t_ype, type); } else t_ype=0; } //------------------------------------ #if !defined(KMIME_NEW_STYLE_CLASSTREE) //---------------------------------- void MessageID::from7BitString(const Q3CString &s) { m_id=s; } Q3CString MessageID::as7BitString(bool incType) { if(incType) return ( typeIntro()+m_id ); else return m_id; } void MessageID::fromUnicodeString(const QString &s, const Q3CString&) { m_id=s.latin1(); //Message-Ids can only contain us-ascii chars } QString MessageID::asUnicodeString() { return QString::fromLatin1(m_id); } void MessageID::generate(const Q3CString &fqdn) { m_id="<"+uniqueString()+"@"+fqdn+">"; } //--------------------------------- #endif //------------------------------------ void Control::from7BitString(const Q3CString &s) { c_trlMsg=s; } Q3CString Control::as7BitString(bool incType) { if(incType) return ( typeIntro()+c_trlMsg ); else return c_trlMsg; } void Control::fromUnicodeString(const QString &s, const Q3CString&) { c_trlMsg=s.latin1(); } QString Control::asUnicodeString() { return QString::fromLatin1(c_trlMsg); } //----------------------------------- #if !defined(KMIME_NEW_STYLE_CLASSTREE) //------------------------------- void AddressField::from7BitString(const Q3CString &s) { int pos1=0, pos2=0, type=0; Q3CString n; //so what do we have here ? if(QString(s).contains( QRegExp("*@*(*)", false, true) )) type=2; // From: foo@bar.com (John Doe) else if(QString(s).contains( QRegExp("*<*@*>", false, true) )) type=1; // From: John Doe else if(QString(s).contains( QRegExp("*@*", false, true) )) type=0; // From: foo@bar.com else { //broken From header => just decode it n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS()); return; } switch(type) { case 0: e_mail=s.copy(); break; case 1: pos1=0; pos2=s.find('<'); if(pos2!=-1) { n=s.mid(pos1, pos2-pos1).trimmed(); pos1=pos2+1; pos2=s.find('>', pos1); if(pos2!=-1) e_mail=s.mid(pos1, pos2-pos1); } else return; break; case 2: pos1=0; pos2=s.find('('); if(pos2!=-1) { e_mail=s.mid(pos1, pos2-pos1).trimmed(); pos1=pos2+1; pos2=s.find(')', pos1); if(pos2!=-1) n=s.mid(pos1, pos2-pos1).trimmed(); } break; default: break; } if(!n.isEmpty()) { removeQuots(n); n_ame=decodeRFC2047String(n, &e_ncCS, defaultCS(), forceCS()); } } Q3CString AddressField::as7BitString(bool incType) { Q3CString ret; if(incType && type()[0]!='\0') ret=typeIntro(); if(n_ame.isEmpty()) ret+=e_mail; else { if (isUsAscii(n_ame)) { Q3CString tmp(n_ame.latin1()); addQuotes(tmp, false); ret+=tmp; } else { ret+=encodeRFC2047String(n_ame, e_ncCS, true); } if (!e_mail.isEmpty()) ret += " <"+e_mail+">"; } return ret; } void AddressField::fromUnicodeString(const QString &s, const Q3CString &cs) { int pos1=0, pos2=0, type=0; Q3CString n; e_ncCS=cachedCharset(cs); //so what do we have here ? if(s.find( QRegExp("*@*(*)", false, true) )!=-1) type=2; // From: foo@bar.com (John Doe) else if(s.find( QRegExp("*<*@*>", false, true) )!=-1) type=1; // From: John Doe else if(s.find( QRegExp("*@*", false, true) )!=-1) type=0; // From: foo@bar.com else { //broken From header => just copy it n_ame=s; return; } switch(type) { case 0: e_mail=s.latin1(); break; case 1: pos1=0; pos2=s.find('<'); if(pos2!=-1) { n_ame=s.mid(pos1, pos2-pos1).trimmed(); pos1=pos2+1; pos2=s.find('>', pos1); if(pos2!=-1) e_mail=s.mid(pos1, pos2-pos1).latin1(); } else return; break; case 2: pos1=0; pos2=s.find('('); if(pos2!=-1) { e_mail=s.mid(pos1, pos2-pos1).trimmed().latin1(); pos1=pos2+1; pos2=s.find(')', pos1); if(pos2!=-1) n_ame=s.mid(pos1, pos2-pos1).trimmed(); } break; default: break; } if(!n_ame.isEmpty()) removeQuots(n_ame); } QString AddressField::asUnicodeString() { if(n_ame.isEmpty()) return QString(e_mail); else { QString s = n_ame; if (!e_mail.isEmpty()) s += " <"+e_mail+">"; return s; } } Q3CString AddressField::nameAs7Bit() { return encodeRFC2047String(n_ame, e_ncCS); } void AddressField::setNameFrom7Bit(const Q3CString &s) { n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS()); } //------------------------------ #endif //------------------------------- bool MailCopiesTo::isValid() { if (hasEmail()) return true; if ((n_ame == "nobody") || (n_ame == "never") || (n_ame == "poster") || (n_ame == "always")) return true; else return false; } bool MailCopiesTo::alwaysCopy() { return (hasEmail() || (n_ame == "poster") || (n_ame == "always")); } bool MailCopiesTo::neverCopy() { return ((n_ame == "nobody") || (n_ame == "never")); } //------------------------------ //--------------------------------------- void Date::from7BitString(const Q3CString &s) { t_ime=KRFCDate::parseDate(s); } Q3CString Date::as7BitString(bool incType) { if(incType) return ( typeIntro()+KRFCDate::rfc2822DateString(t_ime) ); else return Q3CString(KRFCDate::rfc2822DateString(t_ime)); } void Date::fromUnicodeString(const QString &s, const Q3CString&) { from7BitString( Q3CString(s.latin1()) ); } QString Date::asUnicodeString() { return QString::fromLatin1(as7BitString(false)); } QDateTime Date::qdt() { QDateTime dt; dt.setTime_t(t_ime); return dt; } int Date::ageInDays() { QDate today=QDate::currentDate(); return ( qdt().date().daysTo(today) ); } //-------------------------------------- #if !defined(KMIME_NEW_STYLE_CLASSTREE) //----------------------------------------- void To::from7BitString(const Q3CString &s) { qDeleteAll( a_ddrList ); a_ddrList.clear(); QList split = s.split( ',' ); foreach ( QByteArray s, split ) a_ddrList.append( new AddressField( p_arent, s ) ); e_ncCS = cachedCharset( a_ddrList.first()->rfc2047Charset() ); } Q3CString To::as7BitString(bool incType) { Q3CString ret; if(incType) ret+=typeIntro(); if ( !a_ddrList.isEmpty() ) { ObsAddressList::Iterator it = a_ddrList.begin(); if ( *it ) ret += (*it)->as7BitString( false ); for ( ++it; it != a_ddrList.end(); ++it ) ret += "," + (*it)->as7BitString( false ); } return ret; } void To::fromUnicodeString(const QString &s, const Q3CString &cs) { qDeleteAll( a_ddrList ); a_ddrList.clear(); QStringList l = s.split( ',' ); for ( QStringList::Iterator it=l.begin(); it != l.end(); ++it ) a_ddrList.append( new AddressField( p_arent, (*it), cs ) ); e_ncCS=cachedCharset(cs); } QString To::asUnicodeString() { if ( a_ddrList.isEmpty() ) return QString(); QString ret; ObsAddressList::Iterator it = a_ddrList.begin(); if ( *it ) ret += (*it)->asUnicodeString(); for ( ++it; it != a_ddrList.end(); ++it ) ret += "," + (*it)->asUnicodeString(); return ret; } void To::addAddress(const AddressField &a) { AddressField *add=new AddressField(a); add->setParent(p_arent); a_ddrList.append( add ); } QList To::emails() const { QList l; for ( ObsAddressList::ConstIterator it = a_ddrList.begin(); it != a_ddrList.end(); ++it ) if ( (*it)->hasEmail() ) l.append( (*it)->email() ); return l; } //---------------------------------------- #endif //--------------------------------- void Newsgroups::from7BitString(const Q3CString &s) { g_roups=s; e_ncCS=cachedCharset("UTF-8"); } Q3CString Newsgroups::as7BitString(bool incType) { if(incType) return (typeIntro()+g_roups); else return g_roups; } void Newsgroups::fromUnicodeString(const QString &s, const Q3CString&) { g_roups=s.utf8(); e_ncCS=cachedCharset("UTF-8"); } QString Newsgroups::asUnicodeString() { return QString::fromUtf8(g_roups); } Q3CString Newsgroups::firstGroup() { int pos=0; if(!g_roups.isEmpty()) { pos=g_roups.find(','); if(pos==-1) return g_roups; else return g_roups.left(pos); } else return Q3CString(); } QStringList Newsgroups::getGroups() { QStringList temp = QStringList::split(',', g_roups); QStringList ret; QString s; for (QStringList::Iterator it = temp.begin(); it != temp.end(); ++it ) { s = (*it).simplified(); ret.append(s); } return ret; } //-------------------------------- //-------------------------------------- void Lines::from7BitString(const Q3CString &s) { l_ines=s.toInt(); e_ncCS=cachedCharset(Latin1); } Q3CString Lines::as7BitString(bool incType) { Q3CString num; num.setNum(l_ines); if(incType) return ( typeIntro()+num ); else return num; } void Lines::fromUnicodeString(const QString &s, const Q3CString&) { l_ines=s.toInt(); e_ncCS=cachedCharset(Latin1); } QString Lines::asUnicodeString() { QString num; num.setNum(l_ines); return num; } //------------------------------------- #if !defined(KMIME_NEW_STYLE_CLASSTREE) //--------------------------------- void References::from7BitString(const Q3CString &s) { r_ef=s; e_ncCS=cachedCharset(Latin1); } Q3CString References::as7BitString(bool incType) { if(incType) return ( typeIntro()+r_ef ); else return r_ef; } void References::fromUnicodeString(const QString &s, const Q3CString&) { r_ef=s.latin1(); e_ncCS=cachedCharset(Latin1); } QString References::asUnicodeString() { return QString::fromLatin1(r_ef); } int References::count() { int cnt1=0, cnt2=0; unsigned int r_efLen=r_ef.length(); char *dataPtr=r_ef.data(); for(unsigned int i=0; i') cnt2++; } if(cnt1', p_os); p_os=0; if(pos2!=-1) { pos1=r_ef.findRev('<', pos2); if(pos1!=-1) { ret=r_ef.mid(pos1, pos2-pos1+1); p_os=pos1; } } } return ret; } Q3CString References::at(unsigned int i) { Q3CString ret; int pos1=0, pos2=0; unsigned int cnt=0; while(pos1!=-1 && cnt < i+1) { pos2=pos1-1; pos1=r_ef.findRev('<', pos2); cnt++; } if(pos1!=-1) { pos2=r_ef.find('>', pos1); if(pos2!=-1) ret=r_ef.mid(pos1, pos2-pos1+1); } return ret; } void References::append(const Q3CString &s) { QString temp=r_ef.data(); temp += " "; temp += s.data(); QStringList lst=QStringList::split(' ',temp); QRegExp exp("^<.+@.+>$"); // remove bogus references QStringList::Iterator it = lst.begin(); while (it != lst.end()) { if (-1==(*it).find(exp)) it = lst.remove(it); else it++; } if (lst.isEmpty()) { r_ef = s.copy(); // shouldn't happen... return; } else r_ef = ""; temp = lst.first(); // include the first id r_ef = temp.latin1(); lst.remove(temp); // avoids duplicates int insPos = r_ef.length(); for (int i=1;i<=3;i++) { // include the last three ids if (!lst.isEmpty()) { temp = lst.last(); r_ef.insert(insPos,(QString(" %1").arg(temp)).latin1()); lst.remove(temp); } else break; } while (!lst.isEmpty()) { // now insert the rest, up to 1000 characters temp = lst.last(); if ((15+r_ef.length()+temp.length())<1000) { r_ef.insert(insPos,(QString(" %1").arg(temp)).latin1()); lst.remove(temp); } else return; } } //-------------------------------- #endif //---------------------------------- void UserAgent::from7BitString(const Q3CString &s) { u_agent=s; e_ncCS=cachedCharset(Latin1); } Q3CString UserAgent::as7BitString(bool incType) { if(incType) return ( typeIntro()+u_agent ); else return u_agent; } void UserAgent::fromUnicodeString(const QString &s, const Q3CString&) { u_agent=s.latin1(); e_ncCS=cachedCharset(Latin1); } QString UserAgent::asUnicodeString() { return QString::fromLatin1(u_agent); } //--------------------------------- #if !defined(KMIME_NEW_STYLE_CLASSTREE) //------------------------------- void ContentType::from7BitString(const Q3CString &s) { int pos=s.find(';'); if(pos==-1) m_imeType=s.simplified(); else { m_imeType=s.left(pos).simplified(); p_arams=s.mid(pos, s.length()-pos).simplified(); } if(isMultipart()) c_ategory=CCcontainer; else c_ategory=CCsingle; e_ncCS=cachedCharset(Latin1); } Q3CString ContentType::as7BitString(bool incType) { if(incType) return (typeIntro()+m_imeType+p_arams); else return (m_imeType+p_arams); } void ContentType::fromUnicodeString(const QString &s, const Q3CString&) { from7BitString( Q3CString(s.latin1()) ); } QString ContentType::asUnicodeString() { return QString::fromLatin1(as7BitString(false)); } Q3CString ContentType::mediaType() { int pos=m_imeType.find('/'); if(pos==-1) return m_imeType; else return m_imeType.left(pos); } Q3CString ContentType::subType() { int pos=m_imeType.find('/'); if(pos==-1) return Q3CString(); else return m_imeType.mid(pos, m_imeType.length()-pos); } void ContentType::setMimeType(const Q3CString &s) { p_arams.resize(0); m_imeType=s; if(isMultipart()) c_ategory=CCcontainer; else c_ategory=CCsingle; } bool ContentType::isMediatype(const char *s) { return ( strncasecmp(m_imeType.data(), s, strlen(s)) ); } bool ContentType::isSubtype(const char *s) { char *c=strchr(m_imeType.data(), '/'); if( (c==0) || (*(c+1)=='\0') ) return false; else return ( strcasecmp(c+1, s)==0 ); } bool ContentType::isText() { return (strncasecmp(m_imeType.data(), "text", 4)==0); } bool ContentType::isPlainText() { return (strcasecmp(m_imeType.data(), "text/plain")==0); } bool ContentType::isHTMLText() { return (strcasecmp(m_imeType.data(), "text/html")==0); } bool ContentType::isImage() { return (strncasecmp(m_imeType.data(), "image", 5)==0); } bool ContentType::isMultipart() { return (strncasecmp(m_imeType.data(), "multipart", 9)==0); } bool ContentType::isPartial() { return (strcasecmp(m_imeType.data(), "message/partial")==0); } Q3CString ContentType::charset() { Q3CString ret=getParameter("charset"); if( ret.isEmpty() || forceCS() ) { //we return the default-charset if necessary ret=defaultCS(); } return ret; } void ContentType::setCharset(const Q3CString &s) { setParameter("charset", s); } Q3CString ContentType::boundary() { return getParameter("boundary"); } void ContentType::setBoundary(const Q3CString &s) { setParameter("boundary", s, true); } QString ContentType::name() { const char *dummy=0; return ( decodeRFC2047String(getParameter("name"), &dummy, defaultCS(), forceCS()) ); } void ContentType::setName(const QString &s, const Q3CString &cs) { e_ncCS=cs; if (isUsAscii(s)) { Q3CString tmp(s.latin1()); addQuotes(tmp, true); setParameter("name", tmp, false); } else { // FIXME: encoded words can't be enclosed in quotes!! setParameter("name", encodeRFC2047String(s, cs), true); } } Q3CString ContentType::id() { return (getParameter("id")); } void ContentType::setId(const Q3CString &s) { setParameter("id", s, true); } int ContentType::partialNumber() { Q3CString p=getParameter("number"); if(!p.isEmpty()) return p.toInt(); else return -1; } int ContentType::partialCount() { Q3CString p=getParameter("total"); if(!p.isEmpty()) return p.toInt(); else return -1; } void ContentType::setPartialParams(int total, int number) { Q3CString num; num.setNum(number); setParameter("number", num); num.setNum(total); setParameter("total", num); } Q3CString ContentType::getParameter(const char *name) { Q3CString ret; int pos1=0, pos2=0; pos1=QString(p_arams).indexOf(name, 0, Qt::CaseInsensitive); if(pos1!=-1) { if( (pos2=p_arams.indexOf(';', pos1))==-1 ) pos2=p_arams.length(); pos1+=strlen(name)+1; ret=p_arams.mid(pos1, pos2-pos1); removeQuots(ret); } return ret; } void ContentType::setParameter(const Q3CString &name, const Q3CString &value, bool doubleQuotes) { int pos1=0, pos2=0; QByteArray param; if(doubleQuotes) param=name+"=\""+value+"\""; else param=name+"="+value; pos1=QString(p_arams).indexOf(name, 0, Qt::CaseInsensitive); if(pos1==-1) { p_arams+="; "+param; } else { pos2=p_arams.find(';', pos1); if(pos2==-1) pos2=p_arams.length(); p_arams.remove(pos1, pos2-pos1); p_arams.insert(pos1, param); } } //------------------------------ //--------------------------------- typedef struct { const char *s; int e; } encTableType; static const encTableType encTable[] = { { "7Bit", CE7Bit }, { "8Bit", CE8Bit }, { "quoted-printable", CEquPr }, { "base64", CEbase64 }, { "x-uuencode", CEuuenc }, { "binary", CEbinary }, { 0, 0} }; void CTEncoding::from7BitString(const Q3CString &s) { Q3CString stripped(s.simplified()); c_te=CE7Bit; for(int i=0; encTable[i].s!=0; i++) if(strcasecmp(stripped.data(), encTable[i].s)==0) { c_te=(contentEncoding)encTable[i].e; break; } d_ecoded=( c_te==CE7Bit || c_te==CE8Bit ); e_ncCS=cachedCharset(Latin1); } Q3CString CTEncoding::as7BitString(bool incType) { Q3CString str; for(int i=0; encTable[i].s!=0; i++) if(c_te==encTable[i].e) { str=encTable[i].s; break; } if(incType) return ( typeIntro()+str ); else return str; } void CTEncoding::fromUnicodeString(const QString &s, const Q3CString&) { from7BitString( Q3CString(s.latin1()) ); } QString CTEncoding::asUnicodeString() { return QString::fromLatin1(as7BitString(false)); } //-------------------------------- //------------------------------- void CDisposition::from7BitString(const Q3CString &s) { if(strncasecmp(s.data(), "attachment", 10)==0) d_isp=CDattachment; else d_isp=CDinline; int pos=QString(s).indexOf("filename=", 0, Qt::CaseInsensitive); Q3CString fn; if(pos>-1) { pos+=9; fn=s.mid(pos, s.length()-pos); removeQuots(fn); f_ilename=decodeRFC2047String(fn, &e_ncCS, defaultCS(), forceCS()); } } Q3CString CDisposition::as7BitString(bool incType) { Q3CString ret; if(d_isp==CDattachment) ret="attachment"; else ret="inline"; if(!f_ilename.isEmpty()) { if (isUsAscii(f_ilename)) { Q3CString tmp(f_ilename.latin1()); addQuotes(tmp, true); ret+="; filename="+tmp; } else { // FIXME: encoded words can't be enclosed in quotes!! ret+="; filename=\""+encodeRFC2047String(f_ilename, e_ncCS)+"\""; } } if(incType) return ( typeIntro()+ret ); else return ret; } void CDisposition::fromUnicodeString(const QString &s, const Q3CString &cs) { if(strncasecmp(s.latin1(), "attachment", 10)==0) d_isp=CDattachment; else d_isp=CDinline; int pos=s.find("filename=", 0, false); if(pos>-1) { pos+=9; f_ilename=s.mid(pos, s.length()-pos); removeQuots(f_ilename); } e_ncCS=cachedCharset(cs); } QString CDisposition::asUnicodeString() { QString ret; if(d_isp==CDattachment) ret="attachment"; else ret="inline"; if(!f_ilename.isEmpty()) ret+="; filename=\""+f_ilename+"\""; return ret; } //------------------------------ #endif } // namespace Headers } // namespace KMime diff --git a/kmime/kmime_headers.h b/kmime/kmime_headers.h index ac588e0ac..58464228a 100644 --- a/kmime/kmime_headers.h +++ b/kmime/kmime_headers.h @@ -1,864 +1,864 @@ /* -*- c++ -* kmime_headers.h KMime, the KDE internet mail/usenet news message library. Copyright (c) 2001-2002 the KMime authors. See file AUTHORS for details This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2.0 as published by the Free Software Foundation. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #ifndef __KMIME_HEADERS_H__ #define __KMIME_HEADERS_H__ // Content: // // - header's base class defining the common interface // - generic base classes for different types of fields // - incompatible, GStructured-based field classes // - compatible, GUnstructured-based field classes #include "kmime_header_parsing.h" #include #include #include #include #include #include #include #include //Added by qt3to4: #include #include #include #include namespace KMime { //forward declaration class Content; namespace Headers { enum contentCategory { CCsingle, CCcontainer, CCmixedPart, CCalternativePart }; enum contentEncoding { CE7Bit, CE8Bit, CEquPr, CEbase64, CEuuenc, CEbinary }; enum contentDisposition { CDinline, CDattachment, CDparallel }; //often used charset static const QByteArray Latin1("ISO-8859-1"); #define mk_trivial_subclass_with_name( subclass, subclassName, baseclass ) \ class subclass : public Generics::baseclass { \ public: \ subclass() : Generics::baseclass() {} \ subclass( Content * p ) : Generics::baseclass( p ) {} \ subclass( Content * p, const Q3CString & s ) \ : Generics::baseclass( p ) { from7BitString( s ); } \ subclass( Content * p, const QString & s, const Q3CString & cs ) \ : Generics::baseclass( p ) { fromUnicodeString( s, cs ); } \ ~subclass() {} \ \ const char * type() const { return #subclassName; } \ } #define mk_trivial_subclass( subclass, baseclass ) \ mk_trivial_subclass_with_name( subclass, subclass, baseclass ) #define mk_parsing_subclass_with_name( subclass, subclassName, baseclass ) \ class subclass : public Generics::baseclass { \ public: \ subclass() : Generics::baseclass() {} \ subclass( Content * p ) : Generics::baseclass( p ) {} \ subclass( Content * p, const Q3CString & s ) \ : Generics::baseclass( p ) { from7BitString( s ); } \ subclass( Content * p, const QString & s, const Q3CString & cs ) \ : Generics::baseclass( p ) { fromUnicodeString( s, cs ); } \ ~subclass() {} \ \ const char * type() const { return #subclassName; } \ protected: \ bool parse( const char* & scursor, const char * const send, bool isCRLF=false ); \ } #define mk_parsing_subclass( subclass, baseclass ) \ mk_parsing_subclass_with_name( subclass, subclass, baseclass ) // // // HEADER'S BASE CLASS. DEFINES THE COMMON INTERFACE // // /** Baseclass of all header-classes. It represents a header-field as described in RFC-822. */ class KDE_EXPORT Base { public: - typedef Q3PtrList List; + typedef QList List; /** Create an empty header. */ Base() : e_ncCS(0), p_arent(0) {} /** Create an empty header with a parent-content. */ Base(KMime::Content *parent) : e_ncCS(0), p_arent(parent) {} /** Destructor */ virtual ~Base() {} /** Return the parent of this header. */ KMime::Content* parent() { return p_arent; } /** Set the parent for this header. */ void setParent(KMime::Content *p) { p_arent=p; } /** Parse the given string. Take care of RFC2047-encoded strings. A default charset is given. If the last parameter is true the default charset is used in any case */ virtual void from7BitString(const Q3CString&) {} /** Return the encoded header. The parameter specifies whether the header-type should be included. */ virtual Q3CString as7BitString(bool=true) { return Q3CString(); } /** Return the charset that is used for RFC2047-encoding */ Q3CString rfc2047Charset(); /** Set the charset for RFC2047-encoding */ void setRFC2047Charset(const Q3CString &cs); /** Return the default charset */ QByteArray defaultCS(); /** Return if the default charset is mandatory */ bool forceCS(); /** Parse the given string and set the charset. */ virtual void fromUnicodeString(const QString&, const Q3CString&) {} /** Return the decoded content of the header without the header-type. */ virtual QString asUnicodeString() { return QString(); } /** Delete */ virtual void clear() {} /** Do we have data? */ virtual bool isEmpty() { return false; } /** Return the type of this header (e.g. "From") */ virtual const char* type() { return ""; } /** Check if this header is of type t. */ bool is(const char* t) { return (strcasecmp(t, type())==0); } /** Check if this header is a MIME header */ bool isMimeHeader() { return (strncasecmp(type(), "Content-", 8)==0); } /** Check if this header is a X-Header */ bool isXHeader() { return (strncmp(type(), "X-", 2)==0); } protected: Q3CString typeIntro() { return (Q3CString(type())+": "); } const char *e_ncCS; Content *p_arent; }; // // // GENERIC BASE CLASSES FOR DIFFERENT TYPES OF FIELDS // // namespace Generics { /** Abstract base class for unstructured header fields (e.g. "Subject", "Comment", "Content-description"). Features: Decodes the header according to RFC2047, incl. RFC2231 extensions to encoded-words. Subclasses need only re-implement @p const @p char* @p type(). A macro to automate this is named \code MK_TRIVIAL_GUnstructured_SUBCLASS(classname,headername); \endcode The ContentDescription class then reads: \code MK_TRIVIAL_GUnstructured_SUBCLASS(ContentDescription,Content-Description); \endcode */ // known issues: // - uses old decodeRFC2047String function, instead of our own... class KDE_EXPORT GUnstructured : public Base { public: GUnstructured() : Base() {} GUnstructured( Content * p ) : Base( p ) {} GUnstructured( Content * p, const Q3CString & s ) : Base( p ) { from7BitString(s); } GUnstructured( Content * p, const QString & s, const Q3CString & cs ) : Base( p ) { fromUnicodeString( s, cs ); } ~GUnstructured() {} virtual void from7BitString( const Q3CString& str ); virtual Q3CString as7BitString( bool withHeaderType=true ); virtual void fromUnicodeString( const QString & str, const Q3CString & suggestedCharset); virtual QString asUnicodeString(); virtual void clear() { d_ecoded.truncate(0); } virtual bool isEmpty() { return (d_ecoded.isEmpty()); } private: QString d_ecoded; }; /** This is the base class for all structured header fields. It contains parsing methods for all basic token types found in rfc2822. @section Parsing At the basic level, there are tokens & tspecials (rfc2045), atoms & specials, quoted-strings, domain-literals (all rfc822) and encoded-words (rfc2047). As a special token, we have the comment. It is one of the basic tokens defined in rfc822, but it's parsing relies in part on the basic token parsers (e.g. comments may contain encoded-words). Also, most upper-level parsers (notably those for phrase and dot-atom) choose to ignore any comment when parsing. Then there are the real composite tokens, which are made up of one or more of the basic tokens (and semantically invisible comments): phrases (rfc822 with rfc2047) and dot-atoms (rfc2822). This finishes the list of supported token types. Subclasses will provide support for more higher-level tokens, where necessary, using these parsers. @short Base class for structured header fields. @author Marc Mutz */ class KDE_EXPORT GStructured : public Base { public: GStructured() : Base() {} GStructured( Content * p ) : Base( p ) {} GStructured( Content * p, const Q3CString & s ) : Base( p ) { from7BitString(s); } GStructured( Content * p, const QString & s, const Q3CString & cs ) : Base( p ) { fromUnicodeString( s, cs ); } ~GStructured() {} protected: #if 0 // the assembly squad: bool writeAtom( char* & dcursor, const char * const dend, const QString & input ); bool writeAtom( char* & dcursor, const char * const dend, const QPair & input ); bool writeToken( char* & dcursor, const char * const dend, const QString & input ); bool writeToken( char* & dcursor, const char * const dend, const QPair & input ); bool writeGenericQuotedString( char* & dcursor, const char * const dend, const QString & input, bool withCRLF=false ); bool writeComment( char* & dcursor, const char * const dend, const QString & input, bool withCRLF=false ); bool writePhrase( char* & dcursor, const char * const dend, const QString & input, bool withCRLF=false ); bool writeDotAtom( char* & dcursor, const char * const dend, const QString & input, bool withCRLF=false ); #endif }; class KDE_EXPORT GAddress : public GStructured { public: GAddress() : GStructured() {} GAddress( Content * p ) : GStructured( p ) {} GAddress( Content * p, const Q3CString & s ) : GStructured( p ) { from7BitString(s); } GAddress( Content * p, const QString & s, const Q3CString & cs ) : GStructured( p ) { fromUnicodeString( s, cs ); } ~GAddress() {} protected: }; /** Base class for headers that deal with (possibly multiple) addresses, but don't allow groups: */ class KDE_EXPORT MailboxList : public GAddress { public: MailboxList() : GAddress() {} MailboxList( Content * p ) : GAddress( p ) {} MailboxList( Content * p, const Q3CString & s ) : GAddress( p ) { from7BitString(s); } MailboxList( Content * p, const QString & s, const Q3CString & cs ) : GAddress( p ) { fromUnicodeString( s, cs ); } ~MailboxList() {} protected: bool parse( const char* & scursor, const char * const send, bool isCRLF=false ); /** The list of mailboxes */ QList mMailboxList; }; /** Base class for headers that deal with exactly one mailbox (e.g. Sender) */ mk_parsing_subclass(SingleMailbox,MailboxList); /** Base class for headers that deal with (possibly multiple) addresses, allowing groups. */ class KDE_EXPORT AddressList : public GAddress { public: AddressList() : GAddress() {} AddressList( Content * p ) : GAddress( p ) {} AddressList( Content * p, const Q3CString & s ) : GAddress( p ) { from7BitString(s); } AddressList( Content * p, const QString & s, const Q3CString & cs ) : GAddress( p ) { fromUnicodeString( s, cs ); } ~AddressList() {} protected: bool parse( const char* & scursor, const char * const send, bool isCRLF=false ); /** The list of addresses */ QList mAddressList; }; /** Base class for headers which deal with a list of msg-id's */ class KDE_EXPORT GIdent : public GAddress { public: GIdent() : GAddress() {} GIdent( Content * p ) : GAddress( p ) {} GIdent( Content * p, const Q3CString & s ) : GAddress( p ) { from7BitString(s); } GIdent( Content * p, const QString & s, const Q3CString & cs ) : GAddress( p ) { fromUnicodeString( s, cs ); } ~GIdent() {} protected: bool parse( const char* & scursor, const char * const send, bool isCRLF=false ); /** The list of msg-id's */ QList mMsgIdList; }; /** Base class for headers which deal with a list of msg-id's */ mk_parsing_subclass(GSingleIdent,GIdent); /** Base class for headers which deal with a single atom. */ class KDE_EXPORT GToken : public GStructured { public: GToken() : GStructured() {} GToken( Content * p ) : GStructured( p ) {} GToken( Content * p, const Q3CString & s ) : GStructured( p ) { from7BitString(s); } GToken( Content * p, const QString & s, const Q3CString & cs ) : GStructured( p ) { fromUnicodeString( s, cs ); } ~GToken() {} protected: bool parse( const char* & scursor, const char * const send, bool isCRLF=false ); Q3CString mToken; }; class KDE_EXPORT GPhraseList : public GStructured { public: GPhraseList() : GStructured() {} GPhraseList( Content * p ) : GStructured( p ) {} GPhraseList( Content * p, const Q3CString & s ) : GStructured( p ) { from7BitString(s); } GPhraseList( Content * p, const QString & s, const Q3CString & cs ) : GStructured( p ) { fromUnicodeString( s, cs ); } ~GPhraseList() {} protected: bool parse( const char* & scursor, const char * const send, bool isCRLF=false ); QStringList mPhraseList; }; class KDE_EXPORT GDotAtom : public GStructured { public: GDotAtom() : GStructured() {} GDotAtom( Content * p ) : GStructured( p ) {} GDotAtom( Content * p, const Q3CString & s ) : GStructured( p ) { from7BitString(s); } GDotAtom( Content * p, const QString & s, const Q3CString & cs ) : GStructured( p ) { fromUnicodeString( s, cs ); } ~GDotAtom() {} protected: bool parse( const char* & scursor, const char * const send, bool isCRLF=false ); QString mDotAtom; }; class KDE_EXPORT GParametrized : public GStructured { public: GParametrized() : GStructured() {} GParametrized( Content * p ) : GStructured( p ) {} GParametrized( Content * p, const Q3CString & s ) : GStructured( p ) { from7BitString(s); } GParametrized( Content * p, const QString & s, const Q3CString & cs ) : GStructured( p ) { fromUnicodeString( s, cs ); } ~GParametrized() {} protected: QMap mParameterHash; private: }; class KDE_EXPORT GContentType : public GParametrized { public: GContentType() : GParametrized() {} GContentType( Content * p ) : GParametrized( p ) {} GContentType( Content * p, const Q3CString & s ) : GParametrized( p ) { from7BitString(s); } GContentType( Content * p, const QString & s, const Q3CString & cs ) : GParametrized( p ) { fromUnicodeString( s, cs ); } ~GContentType() {} protected: bool parse( const char* & scursor, const char * const send, bool isCRLF=false ); Q3CString mMimeType; Q3CString mMimeSubType; }; class KDE_EXPORT GCISTokenWithParameterList : public GParametrized { public: GCISTokenWithParameterList() : GParametrized() {} GCISTokenWithParameterList( Content * p ) : GParametrized( p ) {} GCISTokenWithParameterList( Content * p, const Q3CString & s ) : GParametrized( p ) { from7BitString(s); } GCISTokenWithParameterList( Content * p, const QString & s, const Q3CString & cs ) : GParametrized( p ) { fromUnicodeString( s, cs ); } ~GCISTokenWithParameterList() {} protected: bool parse( const char* & scursor, const char * const send, bool isCRLF=false ); Q3CString mToken; }; } // namespace Generics // // // INCOMPATIBLE, GSTRUCTURED-BASED FIELDS: // // /** Represents the Return-Path header field. */ class KDE_EXPORT ReturnPath : public Generics::GAddress { public: ReturnPath() : Generics::GAddress() {} ReturnPath( Content * p ) : Generics::GAddress( p ) {} ReturnPath( Content * p, const Q3CString & s ) : Generics::GAddress( p ) { from7BitString(s); } ReturnPath( Content * p, const QString & s, const Q3CString & cs ) : Generics::GAddress( p ) { fromUnicodeString( s, cs ); } ~ReturnPath() {} const char * type() const { return "Return-Path"; } protected: bool parse( const char* & scursor, const char * const send, bool isCRLF=false ); }; #if defined(KMIME_NEW_STYLE_CLASSTREE) // classes whose names collide with earlier ones: // GAddress et al.: // rfc(2)822 headers: mk_trivial_subclass(From,MailboxList); mk_trivial_subclass(Sender,SingleMailbox); mk_trivial_subclass_with_name(ReplyTo,Reply-To,AddressList); mk_trivial_subclass(Cc,AddressList); mk_trivial_subclass(Bcc,AddressList); // usefor headers: mk_trivial_subclass_with_name(MailCopiesTo,Mail-Copies-To,AddressList); // GToken: mk_trivial_subclass_with_name(ContentTransferEncoding, Content-Transfer-Encoding,GToken); // GPhraseList: mk_trivial_subclass(Keywords,GPhraseList); // GDotAtom: mk_trivial_subclass_with_name(MIMEVersion,MIME-Version,GDotAtom); // GIdent: mk_trivial_subclass_with_name(MessageID,Message-ID,GSingleIdent); mk_trivial_subclass_with_name(ContentID,Content-ID,GSingleIdent); mk_trivial_subclass(Supersedes,GSingleIdent); mk_trivial_subclass_with_name(InReplyTo,In-Reply-To,GIdent); mk_trivial_subclass(References,GIdent); // GContentType: mk_trivial_subclass_with_name(ContentType,ContentType,GContentType); // GCISTokenWithParameterList: mk_trivial_subclass_with_name(ContentDisposition,Content-Disposition, GCISTokenWithParameterList); #endif // // // COMPATIBLE GUNSTRUCTURED-BASED FIELDS: // // /** Represents an arbitrary header, that can contain any header-field. Adds a type over GUnstructured. @see GUnstructured */ class KDE_EXPORT Generic : public Generics::GUnstructured { public: Generic() : Generics::GUnstructured(), t_ype(0) {} Generic(const char *t) : Generics::GUnstructured(), t_ype(0) { setType(t); } Generic(const char *t, Content *p) : Generics::GUnstructured( p ), t_ype(0) { setType(t); } Generic(const char *t, Content *p, const Q3CString &s) : Generics::GUnstructured( p, s ), t_ype(0) { setType(t); } Generic(const char *t, Content *p, const QString &s, const Q3CString &cs) : Generics::GUnstructured( p, s, cs ), t_ype(0) { setType(t); } ~Generic() { delete[] t_ype; } virtual void clear() { delete[] t_ype; GUnstructured::clear(); } virtual bool isEmpty() { return (t_ype==0 || GUnstructured::isEmpty()); } virtual const char* type() { return t_ype; } void setType(const char *type); protected: char *t_ype; }; /** Represents a "Subject" header */ class KDE_EXPORT Subject : public Generics::GUnstructured { public: Subject() : Generics::GUnstructured() {} Subject( Content * p ) : Generics::GUnstructured( p ) {} Subject( Content * p, const Q3CString & s ) : Generics::GUnstructured( p, s ) {} Subject( Content * p, const QString & s, const Q3CString & cs ) : Generics::GUnstructured( p, s, cs ) {} ~Subject() {} virtual const char* type() { return "Subject"; } bool isReply() { return ( asUnicodeString().find( QString("Re:"), 0, false ) == 0 ); } }; /** Represents a "Organization" header */ class KDE_EXPORT Organization : public Generics::GUnstructured { public: Organization() : Generics::GUnstructured() {} Organization( Content * p ) : Generics::GUnstructured( p ) {} Organization( Content * p, const Q3CString & s ) : Generics::GUnstructured( p, s ) {}; Organization( Content * p, const QString & s, const Q3CString & cs) : Generics::GUnstructured( p, s, cs ) {} ~Organization() {} virtual const char* type() { return "Organization"; } }; // // // NOT YET CONVERTED STUFF BELOW: // // /** Represents a "Control" header */ class KDE_EXPORT Control : public Base { public: Control() : Base() {} Control(Content *p) : Base(p) {} Control(Content *p, const Q3CString &s) : Base(p) { from7BitString(s); } Control(Content *p, const QString &s) : Base(p) { fromUnicodeString(s, Latin1); } ~Control() {} virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString&); virtual QString asUnicodeString(); virtual void clear() { c_trlMsg.truncate(0); } virtual bool isEmpty() { return (c_trlMsg.isEmpty()); } virtual const char* type() { return "Control"; } bool isCancel() { return QString(c_trlMsg).contains("cancel", Qt::CaseInsensitive); } protected: Q3CString c_trlMsg; }; /** Represents a "Date" header */ class KDE_EXPORT Date : public Base { public: Date() : Base(), t_ime(0) {} Date(Content *p) : Base(p), t_ime(0) {} Date(Content *p, time_t t) : Base(p), t_ime(t) {} Date(Content *p, const Q3CString &s) : Base(p) { from7BitString(s); } Date(Content *p, const QString &s) : Base(p) { fromUnicodeString(s, Latin1); } ~Date() {} virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString&); virtual QString asUnicodeString(); virtual void clear() { t_ime=0; } virtual bool isEmpty() { return (t_ime==0); } virtual const char* type() { return "Date"; } time_t unixTime() { return t_ime; } void setUnixTime(time_t t) { t_ime=t; } void setUnixTime() { t_ime=time(0); } QDateTime qdt(); int ageInDays(); protected: time_t t_ime; }; /** Represents a "Newsgroups" header */ class KDE_EXPORT Newsgroups : public Base { public: Newsgroups() : Base() {} Newsgroups(Content *p) : Base(p) {} Newsgroups(Content *p, const Q3CString &s) : Base(p) { from7BitString(s); } Newsgroups(Content *p, const QString &s) : Base(p) { fromUnicodeString(s, Latin1); } ~Newsgroups() {} virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString&); virtual QString asUnicodeString(); virtual void clear() { g_roups.resize(0); } virtual bool isEmpty() { return g_roups.isEmpty(); } virtual const char* type() { return "Newsgroups"; } Q3CString firstGroup(); bool isCrossposted() { return ( g_roups.find(',')>-1 ); } QStringList getGroups(); protected: Q3CString g_roups; }; /** Represents a "Followup-To" header */ class KDE_EXPORT FollowUpTo : public Newsgroups { public: FollowUpTo() : Newsgroups() {} FollowUpTo(Content *p) : Newsgroups(p) {} FollowUpTo(Content *p, const Q3CString &s) : Newsgroups(p,s) {} FollowUpTo(Content *p, const QString &s) : Newsgroups(p,s) {} ~FollowUpTo() {} virtual const char* type() { return "Followup-To"; } }; /** Represents a "Lines" header */ class KDE_EXPORT Lines : public Base { public: Lines() : Base(),l_ines(-1) {} Lines(Content *p) : Base(p),l_ines(-1) {} Lines(Content *p, unsigned int i) : Base(p),l_ines(i) {} Lines(Content *p, const Q3CString &s) : Base(p) { from7BitString(s); } Lines(Content *p, const QString &s) : Base(p) { fromUnicodeString(s, Latin1); } ~Lines() {} virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString&); virtual QString asUnicodeString(); virtual void clear() { l_ines=-1; } virtual bool isEmpty() { return (l_ines==-1); } virtual const char* type() { return "Lines"; } int numberOfLines() { return l_ines; } void setNumberOfLines(int i) { l_ines=i; } protected: int l_ines; }; /** Represents a "User-Agent" header */ class KDE_EXPORT UserAgent : public Base { public: UserAgent() : Base() {} UserAgent(Content *p) : Base(p) {} UserAgent(Content *p, const Q3CString &s) : Base(p) { from7BitString(s); } UserAgent(Content *p, const QString &s) : Base(p) { fromUnicodeString(s, Latin1); } ~UserAgent() {} virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString&); virtual QString asUnicodeString(); virtual void clear() { u_agent.resize(0); } virtual bool isEmpty() { return (u_agent.isEmpty()); } virtual const char* type() { return "User-Agent"; } protected: Q3CString u_agent; }; #if !defined(KMIME_NEW_STYLE_CLASSTREE) #include "kmime_headers_obs.h" #endif } //namespace Headers #if 0 typedef Headers::Base* (*headerCreator)(void); /** This is a factory for KMime::Headers. You can create new header objects by type with @ref create and @ref upgrade an existing @ref Headers::Generic to a specialized header object. If you are a header class author, you can register your class (let's call it Foo) so:
 
     
@short Factory for KMime::Headers @author Marc Mutz @see KMime::Headers::Base KMime::Headers::Generic */ class HeaderFactory : public Q3AsciiDict { private: HeaderFactory(); ~HeaderFactory() {} static Q3AsciiDict public: /** Create a new header object of type @p aType, or a fitting generic substitute, if available and known */ static Headers::Base* create( const char* aType ) { if (!s_elf) s_elf = new HeaderFactory; headerCreator * hc = (*s_elf)[aType]; if ( !hc ) return 0; else return (*hc)(); } /** This is a wrapper around the above function, provided for convenience. It differs from the above only in what arguments it takes. */ static Headers::Base* create( const Q3CString& aType ) { return create( aType.data() ); } /** Consume @p aType and build a header object that corresponds to the type that @p aType->type() returns. @param aType generic header to upgrade. This will be deleted if necessary, so don't use references to it after calling this function. @return A corresponding header object (if available), or a generic object for this kind of header (if known), or @p aType (else). @see Headers::Generic create */ static Headers::Base* upgrade( Headers::Generic* aType ) { (void)aType; return new Headers::Base; } }; #endif } //namespace KMime #endif // __KMIME_HEADERS_H__ diff --git a/kmime/kmime_headers_obs.h b/kmime/kmime_headers_obs.h index 014d0a1f6..5c118508b 100644 --- a/kmime/kmime_headers_obs.h +++ b/kmime/kmime_headers_obs.h @@ -1,372 +1,371 @@ /* kmime_headers.h KMime, the KDE internet mail/usenet news message library. Copyright (c) 2001 the KMime authors. See file AUTHORS for details This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #ifndef __KMIME_HEADERS_OBS_H__ #define __KMIME_HEADERS_OBS_H__ #if defined(KMIME_NEW_STYLE_CLASSTREE) #error You cannot use this file with the new header classes! #endif #include //Added by qt3to4: #include -#include /** Represents a "Message-Id" header */ class KDE_EXPORT MessageID : public Base { public: MessageID() : Base() {} MessageID(Content *p) : Base(p) {} MessageID(Content *p, const Q3CString &s) : Base(p) { from7BitString(s); } MessageID(Content *p, const QString &s) : Base(p) { fromUnicodeString(s, Latin1); } ~MessageID() {} virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString&); virtual QString asUnicodeString(); virtual void clear() { m_id.resize(0); } virtual bool isEmpty() { return (m_id.isEmpty()); } virtual const char* type() { return "Message-Id"; } void generate(const Q3CString &fqdn); protected: Q3CString m_id; }; /** Represents a "Supersedes" header */ class KDE_EXPORT Supersedes : public MessageID { public: Supersedes() : MessageID() {} Supersedes(Content *p) : MessageID(p) {} Supersedes(Content *p, const Q3CString &s) : MessageID(p,s) {} Supersedes(Content *p, const QString &s) : MessageID(p,s) {} ~Supersedes() {} virtual const char* type() { return "Supersedes"; } }; /** This class encapsulates an address-field, containing an email-address and a real name */ class KDE_EXPORT AddressField : public Base { public: AddressField() : Base() {} AddressField(Content *p) : Base(p) {} AddressField(Content *p, const Q3CString &s) : Base(p) { from7BitString(s); } AddressField(Content *p, const QString &s, const Q3CString &cs) : Base(p) { fromUnicodeString(s, cs); } AddressField(const AddressField &a): Base(a.p_arent) { n_ame=a.n_ame; e_mail=a.e_mail.copy(); e_ncCS=a.e_ncCS; } ~AddressField() {} AddressField& operator=(const AddressField &a) { n_ame=a.n_ame; e_mail=a.e_mail.copy(); e_ncCS=a.e_ncCS; return (*this); } virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString &cs); virtual QString asUnicodeString(); virtual void clear() { n_ame.truncate(0); e_mail.resize(0); } virtual bool isEmpty() { return (e_mail.isEmpty() && n_ame.isEmpty()); } bool hasName() { return ( !n_ame.isEmpty() ); } bool hasEmail() { return ( !e_mail.isEmpty() ); } QString name() { return n_ame; } Q3CString nameAs7Bit(); Q3CString email() { return e_mail; } void setName(const QString &s) { n_ame=s; } void setNameFrom7Bit(const Q3CString &s); void setEmail(const Q3CString &s) { e_mail=s; } protected: QString n_ame; Q3CString e_mail; }; typedef QList ObsAddressList; /** Represent a "From" header */ class KDE_EXPORT From : public AddressField { public: From() : AddressField() {} From(Content *p) : AddressField(p) {} From(Content *p, const Q3CString &s) : AddressField(p,s) {} From(Content *p, const QString &s, const Q3CString &cs) : AddressField(p,s,cs) {} ~From() {} virtual const char* type() { return "From"; } }; /** Represents a "Reply-To" header */ class KDE_EXPORT ReplyTo : public AddressField { public: ReplyTo() : AddressField() {} ReplyTo(Content *p) : AddressField(p) {} ReplyTo(Content *p, const Q3CString &s) : AddressField(p,s) {} ReplyTo(Content *p, const QString &s, const Q3CString &cs) : AddressField(p,s,cs) {} ~ReplyTo() {} virtual const char* type() { return "Reply-To"; } }; /** Represents a "Mail-Copies-To" header http://www.newsreaders.com/misc/mail-copies-to.html */ class KDE_EXPORT MailCopiesTo : public AddressField { public: MailCopiesTo() : AddressField() {} MailCopiesTo(Content *p) : AddressField(p) {} MailCopiesTo(Content *p, const Q3CString &s) : AddressField(p,s) {} MailCopiesTo(Content *p, const QString &s, const Q3CString &cs) : AddressField(p,s,cs) {} ~MailCopiesTo() {} bool isValid(); bool alwaysCopy(); bool neverCopy(); virtual const char* type() { return "Mail-Copies-To"; } }; /** Represents a "To" header */ class KDE_EXPORT To : public Base { public: To() : Base() {} To(Content *p) : Base(p) {} To(Content *p, const Q3CString &s) : Base(p) { from7BitString(s); } To(Content *p, const QString &s, const Q3CString &cs) : Base(p) { fromUnicodeString(s,cs); } ~To() { qDeleteAll( a_ddrList ); a_ddrList.clear(); } virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString &cs); virtual QString asUnicodeString(); virtual void clear() { qDeleteAll( a_ddrList ); a_ddrList.clear(); } virtual bool isEmpty() { return a_ddrList.isEmpty() || a_ddrList.first()->isEmpty(); } virtual const char* type() { return "To"; } void addAddress(const AddressField &a); QList emails() const; protected: ObsAddressList a_ddrList; }; /** Represents a "CC" header */ class KDE_EXPORT CC : public To { public: CC() : To() {} CC(Content *p) : To(p) {} CC(Content *p, const Q3CString &s) : To(p,s) {} CC(Content *p, const QString &s, const Q3CString &cs) : To(p,s,cs) {} ~CC() {} virtual const char* type() { return "CC"; } }; /** Represents a "BCC" header */ class KDE_EXPORT BCC : public To { public: BCC() : To() {} BCC(Content *p) : To(p) {} BCC(Content *p, const Q3CString &s) : To(p,s) {} BCC(Content *p, const QString &s, const Q3CString &cs) : To(p,s,cs) {} ~BCC() {} virtual const char* type() { return "BCC"; } }; /** Represents a "References" header */ class KDE_EXPORT References : public Base { public: References() : Base(),p_os(-1) {} References(Content *p) : Base(p),p_os(-1) {} References(Content *p, const Q3CString &s) : Base(p),p_os(-1) { from7BitString(s); } References(Content *p, const QString &s) : Base(p),p_os(-1) { fromUnicodeString(s, Latin1); } ~References() {} virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString&); virtual QString asUnicodeString(); virtual void clear() { r_ef.resize(0); p_os=0; } virtual bool isEmpty() { return (r_ef.isEmpty()); } virtual const char* type() { return "References"; } int count(); Q3CString first(); Q3CString next(); Q3CString at(unsigned int i); void append(const Q3CString &s); protected: Q3CString r_ef; int p_os; }; /** Represents a "Content-Type" header */ class KDE_EXPORT ContentType : public Base { public: ContentType() : Base(),m_imeType("invalid/invalid"),c_ategory(CCsingle) {} ContentType(Content *p) : Base(p),m_imeType("invalid/invalid"),c_ategory(CCsingle) {} ContentType(Content *p, const Q3CString &s) : Base(p) { from7BitString(s); } ContentType(Content *p, const QString &s) : Base(p) { fromUnicodeString(s, Latin1); } ~ContentType() {} virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString&); virtual QString asUnicodeString(); virtual void clear() { m_imeType.resize(0); p_arams.resize(0); } virtual bool isEmpty() { return (m_imeType.isEmpty()); } virtual const char* type() { return "Content-Type"; } //mime-type handling Q3CString mimeType() { return m_imeType; } Q3CString mediaType(); Q3CString subType(); void setMimeType(const Q3CString &s); bool isMediatype(const char *s); bool isSubtype(const char *s); bool isText(); bool isPlainText(); bool isHTMLText(); bool isImage(); bool isMultipart(); bool isPartial(); //parameter handling Q3CString charset(); void setCharset(const Q3CString &s); Q3CString boundary(); void setBoundary(const Q3CString &s); QString name(); void setName(const QString &s, const Q3CString &cs); Q3CString id(); void setId(const Q3CString &s); int partialNumber(); int partialCount(); void setPartialParams(int total, int number); //category contentCategory category() { return c_ategory; } void setCategory(contentCategory c) { c_ategory=c; } protected: Q3CString getParameter(const char *name); void setParameter(const Q3CString &name, const Q3CString &value, bool doubleQuotes=false); QByteArray m_imeType, p_arams; contentCategory c_ategory; }; /** Represents a "Content-Transfer-Encoding" header */ class KDE_EXPORT CTEncoding : public Base { public: CTEncoding() : Base(),c_te(CE7Bit),d_ecoded(true) {} CTEncoding(Content *p) : Base(p),c_te(CE7Bit),d_ecoded(true) {} CTEncoding(Content *p, const Q3CString &s) : Base(p) { from7BitString(s); } CTEncoding(Content *p, const QString &s) : Base(p) { fromUnicodeString(s, Latin1); } ~CTEncoding() {} virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString&); virtual QString asUnicodeString(); virtual void clear() { d_ecoded=true; c_te=CE7Bit; } virtual const char* type() { return "Content-Transfer-Encoding"; } contentEncoding cte() { return c_te; } void setCte(contentEncoding e) { c_te=e; } bool decoded() { return d_ecoded; } void setDecoded(bool d=true) { d_ecoded=d; } bool needToEncode() { return (d_ecoded && (c_te==CEquPr || c_te==CEbase64)); } protected: contentEncoding c_te; bool d_ecoded; }; /** Represents a "Content-Disposition" header */ class KDE_EXPORT CDisposition : public Base { public: CDisposition() : Base(),d_isp(CDinline) {} CDisposition(Content *p) : Base(p),d_isp(CDinline) {} CDisposition(Content *p, const Q3CString &s) : Base(p) { from7BitString(s); } CDisposition(Content *p, const QString &s, const Q3CString &cs) : Base(p) { fromUnicodeString(s, cs); } ~CDisposition() {} virtual void from7BitString(const Q3CString &s); virtual Q3CString as7BitString(bool incType=true); virtual void fromUnicodeString(const QString &s, const Q3CString &cs); virtual QString asUnicodeString(); virtual void clear() { f_ilename.truncate(0); d_isp=CDinline; } virtual const char* type() { return "Content-Disposition"; } contentDisposition disposition() { return d_isp; } void setDisposition(contentDisposition d) { d_isp=d; } bool isAttachment() { return (d_isp==CDattachment); } QString filename() { return f_ilename; } void setFilename(const QString &s) { f_ilename=s; } protected: contentDisposition d_isp; QString f_ilename; }; /** Represents a "Content-Description" header */ class KDE_EXPORT CDescription : public Generics::GUnstructured { public: CDescription() : Generics::GUnstructured() {} CDescription( Content * p ) : Generics::GUnstructured( p ) {} CDescription( Content * p, const Q3CString & s ) : Generics::GUnstructured( p, s ) {}; CDescription( Content * p, const QString & s, const Q3CString & cs ) : Generics::GUnstructured( p, s, cs ) {} ~CDescription() {} virtual const char* type() { return "Content-Description"; } }; #endif // __KMIME_HEADERS_OBS_H__ diff --git a/kmime/kmime_message.cpp b/kmime/kmime_message.cpp index eb899931c..00b4fa082 100644 --- a/kmime/kmime_message.cpp +++ b/kmime/kmime_message.cpp @@ -1,160 +1,160 @@ /* kmime_message.cpp KMime, the KDE internet mail/usenet news message library. Copyright (c) 2001 the KMime authors. See file AUTHORS for details This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #include "kmime_message.h" using namespace KMime; namespace KMime { Message::Message() { s_ubject.setParent(this); d_ate.setParent(this); } Message::~Message() {} void Message::parse() { Content::parse(); QByteArray raw; if( !(raw=rawHeader(s_ubject.type())).isEmpty() ) s_ubject.from7BitString(raw); if( !(raw=rawHeader(d_ate.type())).isEmpty() ) d_ate.from7BitString(raw); } void Message::assemble() { Headers::Base *h; QByteArray newHead=""; //Message-ID if( (h=messageID(false))!=0 ) newHead+=h->as7BitString()+"\n"; //From h=from(); // "From" is mandatory newHead+=h->as7BitString()+"\n"; //Subject h=subject(); // "Subject" is mandatory newHead+=h->as7BitString()+"\n"; //To if( (h=to(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Reply-To if( (h=replyTo(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Date h=date(); // "Date" is mandatory newHead+=h->as7BitString()+"\n"; //References if( (h=references(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Organization if( (h=organization(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Mime-Version newHead+="MIME-Version: 1.0\n"; //Content-Type newHead+=contentType()->as7BitString()+"\n"; //Content-Transfer-Encoding newHead+=contentTransferEncoding()->as7BitString()+"\n"; //X-Headers int pos=h_ead.find("\nX-"); if(pos>-1) //we already have some x-headers => "recycle" them newHead+=h_ead.mid(pos+1, h_ead.length()-pos-1); else if(h_eaders && !h_eaders->isEmpty()) { - for(h=h_eaders->first(); h; h=h_eaders->next()) { - if( h->isXHeader() && (strncasecmp(h->type(), "X-KNode", 7)!=0) ) - newHead+=h->as7BitString()+"\n"; + foreach ( Headers::Base *h, *h_eaders ) { + if ( h->isXHeader() && ( strncasecmp( h->type(), "X-KNode", 7 ) != 0 ) ) + newHead += h->as7BitString() + '\n'; } } h_ead=newHead; } void Message::clear() { s_ubject.clear(); d_ate.clear(); f_lags.clear(); Content::clear(); } Headers::Base* Message::getHeaderByType(const char *type) { if(strcasecmp("Subject", type)==0) { if(s_ubject.isEmpty()) return 0; else return &s_ubject; } else if(strcasecmp("Date", type)==0){ if(d_ate.isEmpty()) return 0; else return &d_ate; } else return Content::getHeaderByType(type); } void Message::setHeader(Headers::Base *h) { bool del=true; if(h->is("Subject")) s_ubject.fromUnicodeString(h->asUnicodeString(), h->rfc2047Charset()); else if(h->is("Date")) d_ate.setUnixTime( (static_cast(h))->unixTime() ); else { del=false; Content::setHeader(h); } if(del) delete h; } bool Message::removeHeader(const char *type) { if(strcasecmp("Subject", type)==0) s_ubject.clear(); else if(strcasecmp("Date", type)==0) d_ate.clear(); else return Content::removeHeader(type); return true; } } // namespace KMime diff --git a/kmime/kmime_message.h b/kmime/kmime_message.h index 58eeaca48..a524d2a86 100644 --- a/kmime/kmime_message.h +++ b/kmime/kmime_message.h @@ -1,68 +1,66 @@ /* kmime_message.h KMime, the KDE internet mail/usenet news message library. Copyright (c) 2001 the KMime authors. See file AUTHORS for details This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #ifndef __KMIME_MESSAGE_H__ #define __KMIME_MESSAGE_H__ #include "kmime_content.h" #include "kmime_headers.h" #include "boolflags.h" -//Added by qt3to4: -#include namespace KMime { class KDE_EXPORT Message : public Content { public: - typedef Q3PtrList List; + typedef QList List; /** Constructor. Creates an empty message. */ Message(); ~Message(); //content handling virtual void parse(); virtual void assemble(); virtual void clear(); //header access virtual KMime::Headers::Base* getHeaderByType(const char *type); virtual void setHeader(KMime::Headers::Base *h); virtual bool removeHeader(const char *type); virtual KMime::Headers::MessageID* messageID(bool create=true) { KMime::Headers::MessageID *p=0; return getHeaderInstance(p, create); } virtual KMime::Headers::Subject* subject(bool create=true) { if(!create && s_ubject.isEmpty()) return 0; return &s_ubject; } virtual KMime::Headers::Date* date(bool create=true) { if(!create && d_ate.isEmpty()) return 0;return &d_ate; } virtual KMime::Headers::From* from(bool create=true) { KMime::Headers::From *p=0; return getHeaderInstance(p, create); } virtual KMime::Headers::Organization* organization(bool create=true) { KMime::Headers::Organization *p=0; return getHeaderInstance(p, create); } virtual KMime::Headers::ReplyTo* replyTo(bool create=true) { KMime::Headers::ReplyTo *p=0; return getHeaderInstance(p, create); } virtual KMime::Headers::To* to(bool create=true) { KMime::Headers::To *p=0; return getHeaderInstance(p, create); } virtual KMime::Headers::CC* cc(bool create=true) { KMime::Headers::CC *p=0; return getHeaderInstance(p, create); } virtual KMime::Headers::BCC* bcc(bool create=true) { KMime::Headers::BCC *p=0; return getHeaderInstance(p, create); } virtual KMime::Headers::References* references(bool create=true) { KMime::Headers::References *p=0; return getHeaderInstance(p, create); } protected: //hardcoded headers KMime::Headers::Subject s_ubject; KMime::Headers::Date d_ate; BoolFlags f_lags; // some status info }; // class Message } // namespace KMime #endif // __KMIME_MESSAGE_H__ diff --git a/kmime/kmime_newsarticle.cpp b/kmime/kmime_newsarticle.cpp index bc77f5072..b81591273 100644 --- a/kmime/kmime_newsarticle.cpp +++ b/kmime/kmime_newsarticle.cpp @@ -1,160 +1,159 @@ /* kmime_newsarticle.cpp KMime, the KDE internet mail/usenet news message library. Copyright (c) 2001 the KMime authors. See file AUTHORS for details This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #include "kmime_newsarticle.h" using namespace KMime; namespace KMime { void NewsArticle::parse() { Message::parse(); QByteArray raw; if( !(raw=rawHeader(l_ines.type())).isEmpty() ) l_ines.from7BitString(raw); } void NewsArticle::assemble() { Headers::Base *h; QByteArray newHead=""; //Message-ID if( (h=messageID(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Control if( (h=control(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Supersedes if( (h=supersedes(false))!=0 ) newHead+=h->as7BitString()+"\n"; //From h=from(); // "From" is mandatory newHead+=h->as7BitString()+"\n"; //Subject h=subject(); // "Subject" is mandatory newHead+=h->as7BitString()+"\n"; //To if( (h=to(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Newsgroups if( (h=newsgroups(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Followup-To if( (h=followUpTo(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Reply-To if( (h=replyTo(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Mail-Copies-To if( (h=mailCopiesTo(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Date h=date(); // "Date" is mandatory newHead+=h->as7BitString()+"\n"; //References if( (h=references(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Lines h=lines(); // "Lines" is mandatory newHead+=h->as7BitString()+"\n"; //Organization if( (h=organization(false))!=0 ) newHead+=h->as7BitString()+"\n"; //User-Agent if( (h=userAgent(false))!=0 ) newHead+=h->as7BitString()+"\n"; //Mime-Version newHead+="MIME-Version: 1.0\n"; //Content-Type newHead+=contentType()->as7BitString()+"\n"; //Content-Transfer-Encoding newHead+=contentTransferEncoding()->as7BitString()+"\n"; //X-Headers int pos=h_ead.find("\nX-"); if(pos>-1) //we already have some x-headers => "recycle" them newHead+=h_ead.mid(pos+1, h_ead.length()-pos); else if(h_eaders && !h_eaders->isEmpty()) { - for(h=h_eaders->first(); h; h=h_eaders->next()) { - if( h->isXHeader() && (strncasecmp(h->type(), "X-KNode", 7)!=0) ) - newHead+=h->as7BitString()+"\n"; - } + foreach( Headers::Base *h, *h_eaders ) + if ( h->isXHeader() && ( strncasecmp( h->type(), "X-KNode", 7 ) != 0 ) ) + newHead += h->as7BitString() + '\n'; } h_ead=newHead; } void NewsArticle::clear() { l_ines.clear(); Message::clear(); } Headers::Base * NewsArticle::getHeaderByType(const char * type) { if(strcasecmp("Lines", type)==0) { if(l_ines.isEmpty()) return 0; else return &l_ines; } else return Message::getHeaderByType(type); } void NewsArticle::setHeader(Headers::Base *h) { bool del=true; if(h->is("Lines")) l_ines.setNumberOfLines( (static_cast(h))->numberOfLines() ); else { del=false; Message::setHeader(h); } if(del) delete h; } bool NewsArticle::removeHeader(const char *type) { if(strcasecmp("Lines", type)==0) l_ines.clear(); else return Message::removeHeader(type); return true; } } // namespace KMime