You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdepim/libkmime/kmime_headers.cpp

1635 lines
32 KiB

/*
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 "kqcstringsplitter.h"
#include <tqtextcodec.h>
#include <tqstring.h>
#include <tqcstring.h>
#include <tqstringlist.h>
#include <tqvaluelist.h>
#include <kglobal.h>
#include <kcharsets.h>
#include <krfcdate.h>
#include <assert.h>
using namespace KMime;
using namespace KMime::Headers;
using namespace KMime::Types;
using namespace KMime::HeaderParsing;
namespace KMime {
namespace Headers {
//-----<Base>----------------------------------
TQCString Base::rfc2047Charset()
{
if( (e_ncCS==0) || forceCS() )
return defaultCS();
else
return TQCString(e_ncCS);
}
void Base::setRFC2047Charset(const TQCString &cs)
{
e_ncCS=cachedCharset(cs);
}
bool Base::forceCS()
{
return ( p_arent!=0 ? p_arent->forceDefaultCS() : false );
}
TQCString Base::defaultCS()
{
return ( p_arent!=0 ? p_arent->defaultCharset() : Latin1 );
}
//-----</Base>---------------------------------
namespace Generics {
//-----<GUnstructured>-------------------------
void GUnstructured::from7BitString( const TQCString & str )
{
d_ecoded = decodeRFC2047String( str, &e_ncCS, defaultCS(), forceCS() );
}
TQCString GUnstructured::as7BitString( bool withHeaderType )
{
TQCString result;
if ( withHeaderType )
result = typeIntro();
result += encodeRFC2047String( d_ecoded, e_ncCS ) ;
return result;
}
void GUnstructured::fromUnicodeString( const TQString & str,
const TQCString & suggestedCharset )
{
d_ecoded = str;
e_ncCS = cachedCharset( suggestedCharset );
}
TQString GUnstructured::asUnicodeString()
{
return d_ecoded;
}
//-----</GUnstructured>-------------------------
//-----<GStructured>-------------------------
//-----</GStructured>-------------------------
//-----<GAddress>-------------------------
//-----</GAddress>-------------------------
//-----<MailboxList>-------------------------
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:
TQValueList<Address> maybeAddressList;
if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) )
return false;
mMailboxList.clear();
// extract the mailboxes and complain if there are groups:
TQValueList<Address>::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;
}
//-----</MailboxList>-------------------------
//-----<SingleMailbox>-------------------------
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;
}
//-----</SingleMailbox>-------------------------
//-----<AddressList>-------------------------
bool AddressList::parse( const char* & scursor, const char * const send,
bool isCRLF ) {
TQValueList<Address> maybeAddressList;
if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) )
return false;
mAddressList = maybeAddressList;
return true;
}
//-----</AddressList>-------------------------
//-----<GToken>-------------------------
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;
TQPair<const char*,int> maybeToken;
if ( !parseToken( scursor, send, maybeToken, false /* no 8bit chars */ ) )
return false;
mToken = TQCString( 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;
}
//-----</GToken>-------------------------
//-----<GPhraseList>-------------------------
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; }
TQString 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;
}
//-----</GPhraseList>-------------------------
//-----<GDotAtom>-------------------------
bool GDotAtom::parse( const char* & scursor, const char * const send,
bool isCRLF ) {
TQString 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;
}
//-----</GDotAtom>-------------------------
//-----<GParametrized>-------------------------
//-----</GParametrized>-------------------------
//-----</GContentType>-------------------------
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
//
TQPair<const char*,int> maybeMimeType;
if ( !parseToken( scursor, send, maybeMimeType, false /* no 8Bit */ ) )
return false;
mMimeType = TQCString( 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;
TQPair<const char*,int> maybeSubType;
if ( !parseToken( scursor, send, maybeSubType, false /* no 8bit */ ) )
return false;
mMimeSubType = TQCString( 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;
}
//-----</GContentType>-------------------------
//-----<GTokenWithParameterList>-------------------------
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;
TQPair<const char*,int> maybeToken;
if ( !parseToken( scursor, send, maybeToken, false /* no 8Bit */ ) )
return false;
mToken = TQCString( 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;
}
//-----</GTokenWithParameterList>-------------------------
//-----<GIdent>-------------------------
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;
}
//-----</GIdent>-------------------------
//-----<GSingleIdent>-------------------------
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;
}
//-----</GSingleIdent>-------------------------
} // namespace Generics
//-----<ReturnPath>-------------------------
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 = TQString();
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;
}
//-----</ReturnPath>-------------------------
//-----<Generic>-------------------------------
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;
}
//-----<Generic>-------------------------------
#if !defined(KMIME_NEW_STYLE_CLASSTREE)
//-----<MessageID>-----------------------------
void MessageID::from7BitString(const TQCString &s)
{
m_id=s;
}
TQCString MessageID::as7BitString(bool incType)
{
if(incType)
return ( typeIntro()+m_id );
else
return m_id;
}
void MessageID::fromUnicodeString(const TQString &s, const TQCString&)
{
m_id=s.latin1(); //Message-Ids can only contain us-ascii chars
}
TQString MessageID::asUnicodeString()
{
return TQString::tqfromLatin1(m_id);
}
void MessageID::generate(const TQCString &fqdn)
{
m_id="<"+uniqueString()+"@"+fqdn+">";
}
//-----</MessageID>----------------------------
#endif
//-----<Control>-------------------------------
void Control::from7BitString(const TQCString &s)
{
c_trlMsg=s;
}
TQCString Control::as7BitString(bool incType)
{
if(incType)
return ( typeIntro()+c_trlMsg );
else
return c_trlMsg;
}
void Control::fromUnicodeString(const TQString &s, const TQCString&)
{
c_trlMsg=s.latin1();
}
TQString Control::asUnicodeString()
{
return TQString::tqfromLatin1(c_trlMsg);
}
//-----</Control>------------------------------
#if !defined(KMIME_NEW_STYLE_CLASSTREE)
//-----<AddressField>--------------------------
void AddressField::from7BitString(const TQCString &s)
{
int pos1=0, pos2=0, type=0;
TQCString n;
//so what do we have here ?
if(s.tqfind( TQRegExp("*@*(*)", false, true) )!=-1) type=2; // From: foo@bar.com (John Doe)
else if(s.tqfind( TQRegExp("*<*@*>", false, true) )!=-1) type=1; // From: John Doe <foo@bar.com>
else if(s.tqfind( TQRegExp("*@*", false, true) )!=-1) 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.tqfind('<');
if(pos2!=-1) {
n=s.mid(pos1, pos2-pos1).stripWhiteSpace();
pos1=pos2+1;
pos2=s.tqfind('>', pos1);
if(pos2!=-1)
e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace();
}
else return;
break;
case 2:
pos1=0;
pos2=s.tqfind('(');
if(pos2!=-1) {
e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace();
pos1=pos2+1;
pos2=s.tqfind(')', pos1);
if(pos2!=-1)
n=s.mid(pos1, pos2-pos1).stripWhiteSpace();
}
break;
default: break;
}
if(!n.isEmpty()) {
removeQuots(n);
n_ame=decodeRFC2047String(n, &e_ncCS, defaultCS(), forceCS());
}
}
TQCString AddressField::as7BitString(bool incType)
{
TQCString ret;
if(incType && type()[0]!='\0')
ret=typeIntro();
if(n_ame.isEmpty())
ret+=e_mail;
else {
if (isUsAscii(n_ame)) {
TQCString 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 TQString &s, const TQCString &cs)
{
int pos1=0, pos2=0, type=0;
TQCString n;
e_ncCS=cachedCharset(cs);
//so what do we have here ?
if(s.tqfind( TQRegExp("*@*(*)", false, true) )!=-1) type=2; // From: foo@bar.com (John Doe)
else if(s.tqfind( TQRegExp("*<*@*>", false, true) )!=-1) type=1; // From: John Doe <foo@bar.com>
else if(s.tqfind( TQRegExp("*@*", 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.tqfind('<');
if(pos2!=-1) {
n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace();
pos1=pos2+1;
pos2=s.tqfind('>', pos1);
if(pos2!=-1)
e_mail=s.mid(pos1, pos2-pos1).latin1();
}
else return;
break;
case 2:
pos1=0;
pos2=s.tqfind('(');
if(pos2!=-1) {
e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace().latin1();
pos1=pos2+1;
pos2=s.tqfind(')', pos1);
if(pos2!=-1)
n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace();
}
break;
default: break;
}
if(!n_ame.isEmpty())
removeQuots(n_ame);
}
TQString AddressField::asUnicodeString()
{
if(n_ame.isEmpty())
return TQString(e_mail);
else {
TQString s = n_ame;
if (!e_mail.isEmpty())
s += " <"+e_mail+">";
return s;
}
}
TQCString AddressField::nameAs7Bit()
{
return encodeRFC2047String(n_ame, e_ncCS);
}
void AddressField::setNameFrom7Bit(const TQCString &s)
{
n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS());
}
//-----</AddressField>-------------------------
#endif
//-----<MailCopiesTo>--------------------------
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"));
}
//-----</MailCopiesTo>-------------------------
//-----<Date>----------------------------------
void Date::from7BitString(const TQCString &s)
{
t_ime=KRFCDate::parseDate(s);
}
TQCString Date::as7BitString(bool incType)
{
if(incType)
return ( typeIntro()+KRFCDate::rfc2822DateString(t_ime) );
else
return TQCString(KRFCDate::rfc2822DateString(t_ime));
}
void Date::fromUnicodeString(const TQString &s, const TQCString&)
{
from7BitString( TQCString(s.latin1()) );
}
TQString Date::asUnicodeString()
{
return TQString::tqfromLatin1(as7BitString(false));
}
TQDateTime Date::qdt()
{
TQDateTime dt;
dt.setTime_t(t_ime);
return dt;
}
int Date::ageInDays()
{
TQDate today=TQDate::tqcurrentDate();
return ( qdt().date().daysTo(today) );
}
//-----</Date>---------------------------------
#if !defined(KMIME_NEW_STYLE_CLASSTREE)
//-----<To>------------------------------------
void To::from7BitString(const TQCString &s)
{
if(a_ddrList)
a_ddrList->clear();
else {
a_ddrList=new TQPtrList<AddressField>;
a_ddrList->setAutoDelete(true);
}
KTQCStringSplitter split;
split.init(s, ",");
bool splitOk=split.first();
if(!splitOk)
a_ddrList->append( new AddressField(p_arent, s ));
else {
do {
a_ddrList->append( new AddressField(p_arent, split.string()) );
} while(split.next());
}
e_ncCS=cachedCharset(a_ddrList->first()->rfc2047Charset());
}
TQCString To::as7BitString(bool incType)
{
TQCString ret;
if(incType)
ret+=typeIntro();
if (a_ddrList) {
AddressField *it=a_ddrList->first();
if (it)
ret+=it->as7BitString(false);
for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() )
ret+=","+it->as7BitString(false);
}
return ret;
}
void To::fromUnicodeString(const TQString &s, const TQCString &cs)
{
if(a_ddrList)
a_ddrList->clear();
else {
a_ddrList=new TQPtrList<AddressField>;
a_ddrList->setAutoDelete(true);
}
TQStringList l=TQStringList::split(",", s);
TQStringList::Iterator it=l.begin();
for(; it!=l.end(); ++it)
a_ddrList->append(new AddressField( p_arent, (*it), cs ));
e_ncCS=cachedCharset(cs);
}
TQString To::asUnicodeString()
{
if(!a_ddrList)
return TQString();
TQString ret;
AddressField *it=a_ddrList->first();
if (it)
ret+=it->asUnicodeString();
for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() )
ret+=","+it->asUnicodeString();
return ret;
}
void To::addAddress(const AddressField &a)
{
if(!a_ddrList) {
a_ddrList=new TQPtrList<AddressField>;
a_ddrList->setAutoDelete(true);
}
AddressField *add=new AddressField(a);
add->setParent(p_arent);
a_ddrList->append(add);
}
void To::emails(TQStrList *l)
{
l->clear();
for (AddressField *it=a_ddrList->first(); it != 0; it=a_ddrList->next() )
if( it->hasEmail() )
l->append( it->email() );
}
void To::names(TQStringList *l)
{
l->clear();
for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() )
if( it->hasName() )
l->append( it->name() );
}
void To::displayNames(TQStringList *l)
{
l->clear();
for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() )
l->append( it->asUnicodeString() );
}
//-----</To>-----------------------------------
#endif
//-----<Newsgroups>----------------------------
void Newsgroups::from7BitString(const TQCString &s)
{
g_roups=s;
e_ncCS=cachedCharset("UTF-8");
}
TQCString Newsgroups::as7BitString(bool incType)
{
if(incType)
return (typeIntro()+g_roups);
else
return g_roups;
}
void Newsgroups::fromUnicodeString(const TQString &s, const TQCString&)
{
g_roups=s.utf8();
e_ncCS=cachedCharset("UTF-8");
}
TQString Newsgroups::asUnicodeString()
{
return TQString::fromUtf8(g_roups);
}
TQCString Newsgroups::firstGroup()
{
int pos=0;
if(!g_roups.isEmpty()) {
pos=g_roups.tqfind(',');
if(pos==-1)
return g_roups;
else
return g_roups.left(pos);
}
else
return TQCString();
}
TQStringList Newsgroups::getGroups()
{
TQStringList temp = TQStringList::split(',', g_roups);
TQStringList ret;
TQString s;
for (TQStringList::Iterator it = temp.begin(); it != temp.end(); ++it ) {
s = (*it).simplifyWhiteSpace();
ret.append(s);
}
return ret;
}
//-----</Newsgroups>---------------------------
//-----<Lines>---------------------------------
void Lines::from7BitString(const TQCString &s)
{
l_ines=s.toInt();
e_ncCS=cachedCharset(Latin1);
}
TQCString Lines::as7BitString(bool incType)
{
TQCString num;
num.setNum(l_ines);
if(incType)
return ( typeIntro()+num );
else
return num;
}
void Lines::fromUnicodeString(const TQString &s, const TQCString&)
{
l_ines=s.toInt();
e_ncCS=cachedCharset(Latin1);
}
TQString Lines::asUnicodeString()
{
TQString num;
num.setNum(l_ines);
return num;
}
//-----</Lines>--------------------------------
#if !defined(KMIME_NEW_STYLE_CLASSTREE)
//-----<References>----------------------------
void References::from7BitString(const TQCString &s)
{
r_ef=s;
e_ncCS=cachedCharset(Latin1);
}
TQCString References::as7BitString(bool incType)
{
if(incType)
return ( typeIntro()+r_ef );
else
return r_ef;
}
void References::fromUnicodeString(const TQString &s, const TQCString&)
{
r_ef=s.latin1();
e_ncCS=cachedCharset(Latin1);
}
TQString References::asUnicodeString()
{
return TQString::tqfromLatin1(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<r_efLen; i++) {
if(dataPtr[i]=='<') cnt1++;
else if(dataPtr[i]=='>') cnt2++;
}
if(cnt1<cnt2) return cnt1;
else return cnt2;
}
TQCString References::first()
{
p_os=-1;
return next();
}
TQCString References::next()
{
int pos1=0, pos2=0;
TQCString ret;
if(p_os!=0) {
pos2=r_ef.findRev('>', 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;
}
TQCString References::at(unsigned int i)
{
TQCString 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.tqfind('>', pos1);
if(pos2!=-1)
ret=r_ef.mid(pos1, pos2-pos1+1);
}
return ret;
}
void References::append(const TQCString &s)
{
TQString temp=r_ef.data();
temp += " ";
temp += s.data();
TQStringList lst=TQStringList::split(' ',temp);
TQRegExp exp("^<.+@.+>$");
// remove bogus references
TQStringList::Iterator it = lst.begin();
while (it != lst.end()) {
if (-1==(*it).tqfind(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,(TQString(" %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,(TQString(" %1").arg(temp)).latin1());
lst.remove(temp);
} else
return;
}
}
//-----</References>---------------------------
#endif
//-----<UserAgent>-----------------------------
void UserAgent::from7BitString(const TQCString &s)
{
u_agent=s;
e_ncCS=cachedCharset(Latin1);
}
TQCString UserAgent::as7BitString(bool incType)
{
if(incType)
return ( typeIntro()+u_agent );
else
return u_agent;
}
void UserAgent::fromUnicodeString(const TQString &s, const TQCString&)
{
u_agent=s.latin1();
e_ncCS=cachedCharset(Latin1);
}
TQString UserAgent::asUnicodeString()
{
return TQString::tqfromLatin1(u_agent);
}
//-----</UserAgent>----------------------------
#if !defined(KMIME_NEW_STYLE_CLASSTREE)
//-----<Content-Type>--------------------------
void ContentType::from7BitString(const TQCString &s)
{
int pos=s.tqfind(';');
if(pos==-1)
m_imeType=s.simplifyWhiteSpace();
else {
m_imeType=s.left(pos).simplifyWhiteSpace();
p_arams=s.mid(pos, s.length()-pos).simplifyWhiteSpace();
}
if(isMultipart())
c_ategory=CCcontainer;
else
c_ategory=CCsingle;
e_ncCS=cachedCharset(Latin1);
}
TQCString ContentType::as7BitString(bool incType)
{
if(incType)
return (typeIntro()+m_imeType+p_arams);
else
return (m_imeType+p_arams);
}
void ContentType::fromUnicodeString(const TQString &s, const TQCString&)
{
from7BitString( TQCString(s.latin1()) );
}
TQString ContentType::asUnicodeString()
{
return TQString::tqfromLatin1(as7BitString(false));
}
TQCString ContentType::mediaType()
{
int pos=m_imeType.tqfind('/');
if(pos==-1)
return m_imeType;
else
return m_imeType.left(pos);
}
TQCString ContentType::subType()
{
int pos=m_imeType.tqfind('/');
if(pos==-1)
return TQCString();
else
return m_imeType.mid(pos, m_imeType.length()-pos);
}
void ContentType::setMimeType(const TQCString &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);
}
TQCString ContentType::charset()
{
TQCString ret=getParameter("charset");
if( ret.isEmpty() || forceCS() ) { //we return the default-charset if necessary
ret=defaultCS();
}
return ret;
}
void ContentType::setCharset(const TQCString &s)
{
setParameter("charset", s);
}
TQCString ContentType::boundary()
{
return getParameter("boundary");
}
void ContentType::setBoundary(const TQCString &s)
{
setParameter("boundary", s, true);
}
TQString ContentType::name()
{
const char *dummy=0;
return ( decodeRFC2047String(getParameter("name"), &dummy, defaultCS(), forceCS()) );
}
void ContentType::setName(const TQString &s, const TQCString &cs)
{
e_ncCS=cs;
if (isUsAscii(s)) {
TQCString 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);
}
}
TQCString ContentType::id()
{
return (getParameter("id"));
}
void ContentType::setId(const TQCString &s)
{
setParameter("id", s, true);
}
int ContentType::partialNumber()
{
TQCString p=getParameter("number");
if(!p.isEmpty())
return p.toInt();
else
return -1;
}
int ContentType::partialCount()
{
TQCString p=getParameter("total");
if(!p.isEmpty())
return p.toInt();
else
return -1;
}
void ContentType::setPartialParams(int total, int number)
{
TQCString num;
num.setNum(number);
setParameter("number", num);
num.setNum(total);
setParameter("total", num);
}
TQCString ContentType::getParameter(const char *name)
{
TQCString ret;
int pos1=0, pos2=0;
pos1=p_arams.tqfind(name, 0, false);
if(pos1!=-1) {
if( (pos2=p_arams.tqfind(';', 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 TQCString &name, const TQCString &value, bool doubleQuotes)
{
int pos1=0, pos2=0;
TQCString param;
if(doubleQuotes)
param=name+"=\""+value+"\"";
else
param=name+"="+value;
pos1=p_arams.tqfind(name, 0, false);
if(pos1==-1) {
p_arams+="; "+param;
}
else {
pos2=p_arams.tqfind(';', pos1);
if(pos2==-1)
pos2=p_arams.length();
p_arams.remove(pos1, pos2-pos1);
p_arams.insert(pos1, param);
}
}
//-----</Content-Type>-------------------------
//-----<CTEncoding>----------------------------
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 TQCString &s)
{
TQCString stripped(s.simplifyWhiteSpace());
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);
}
TQCString CTEncoding::as7BitString(bool incType)
{
TQCString 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 TQString &s, const TQCString&)
{
from7BitString( TQCString(s.latin1()) );
}
TQString CTEncoding::asUnicodeString()
{
return TQString::tqfromLatin1(as7BitString(false));
}
//-----</CTEncoding>---------------------------
//-----<CDisposition>--------------------------
void CDisposition::from7BitString(const TQCString &s)
{
if(strncasecmp(s.data(), "attachment", 10)==0)
d_isp=CDattachment;
else d_isp=CDinline;
int pos=s.tqfind("filename=", 0, false);
TQCString fn;
if(pos>-1) {
pos+=9;
fn=s.mid(pos, s.length()-pos);
removeQuots(fn);
f_ilename=decodeRFC2047String(fn, &e_ncCS, defaultCS(), forceCS());
}
}
TQCString CDisposition::as7BitString(bool incType)
{
TQCString ret;
if(d_isp==CDattachment)
ret="attachment";
else
ret="inline";
if(!f_ilename.isEmpty()) {
if (isUsAscii(f_ilename)) {
TQCString 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 TQString &s, const TQCString &cs)
{
if(strncasecmp(s.latin1(), "attachment", 10)==0)
d_isp=CDattachment;
else d_isp=CDinline;
int pos=s.tqfind("filename=", 0, false);
if(pos>-1) {
pos+=9;
f_ilename=s.mid(pos, s.length()-pos);
removeQuots(f_ilename);
}
e_ncCS=cachedCharset(cs);
}
TQString CDisposition::asUnicodeString()
{
TQString ret;
if(d_isp==CDattachment)
ret="attachment";
else
ret="inline";
if(!f_ilename.isEmpty())
ret+="; filename=\""+f_ilename+"\"";
return ret;
}
//-----</CDisposition>-------------------------
#endif
} // namespace Headers
} // namespace KMime