18#include "kmime_headers.h"
20#include "kmime_util.h"
21#include "kmime_content.h"
22#include "kmime_codecs.h"
23#include "kmime_header_parsing.h"
24#include "kmime_warning.h"
26#include "kqcstringsplitter.h"
28#include <tqtextcodec.h>
31#include <tqstringlist.h>
32#include <tqvaluelist.h>
42using namespace KMime::Headers;
43using namespace KMime::Types;
44using namespace KMime::HeaderParsing;
55 return TQCString(e_ncCS);
61 e_ncCS=cachedCharset(cs);
67 return ( p_arent!=0 ? p_arent->forceDefaultCS() : false );
73 return ( p_arent!=0 ? p_arent->defaultCharset() : Latin1 );
93 result += encodeRFC2047String( d_ecoded, e_ncCS ) ;
99 const TQCString & suggestedCharset )
102 e_ncCS = cachedCharset( suggestedCharset );
130bool MailboxList::parse( const char* & scursor, const char * const send,
137 TQValueList<Address> maybeAddressList;
138 if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) )
144 TQValueList<Address>::Iterator it;
145 for ( it = maybeAddressList.begin(); it != maybeAddressList.end() ; ++it ) {
146 if ( !(*it).displayName.isEmpty() ) {
147 KMIME_WARN << "mailbox groups in header disallowing them! Name: \""
148 << (*it).displayName << "\"" << endl;
161bool SingleMailbox::parse( const char* & scursor, const char * const send,
163 if ( !MailboxList::parse( scursor, send, isCRLF ) ) return false;
165 if ( mMailboxList.count() > 1 ) {
166 KMIME_WARN << "multiple mailboxes in header allowing only a single one!"
178bool AddressList::parse( const char* & scursor, const char * const send,
181 TQValueList<Address> maybeAddressList;
182 if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) )
195bool GToken::parse( const char* & scursor, const char * const send,
198 eatCFWS( scursor, send, isCRLF );
200 if ( scursor == send ) return false;
202 TQPair<const char*,int> maybeToken;
203 if ( !parseToken( scursor, send, maybeToken, false ) )
205 mToken = TQCString( maybeToken.first, maybeToken.second );
208 eatCFWS( scursor, send, isCRLF );
209 if ( scursor != send ) {
210 KMIME_WARN << "trailing garbage after token in header allowing "
211 "only a single token!" << endl;
222bool GPhraseList::parse( const char* & scursor, const char * const send,
227 while ( scursor != send ) {
228 eatCFWS( scursor, send, isCRLF );
230 if ( scursor == send ) return true;
232 if ( *scursor != ',' ) { scursor++; continue; }
234 TQString maybePhrase;
235 if ( !parsePhrase( scursor, send, maybePhrase, isCRLF ) )
237 mPhraseList.append( maybePhrase );
239 eatCFWS( scursor, send, isCRLF );
241 if ( scursor == send ) return true;
243 if ( *scursor != ',' ) scursor++;
254bool GDotAtom::parse( const char* & scursor, const char * const send,
257 TQString maybeDotAtom;
258 if ( !parseDotAtom( scursor, send, maybeDotAtom, isCRLF ) )
261 mDotAtom = maybeDotAtom;
263 eatCFWS( scursor, send, isCRLF );
264 if ( scursor != send ) {
265 KMIME_WARN << "trailing garbage after dot-atom in header allowing "
266 "only a single dot-atom!" << endl;
284bool GContentType::parse( const char* & scursor, const char * const send,
291 mParameterHash.clear();
293 eatCFWS( scursor, send, isCRLF );
294 if ( scursor == send ) {
303 TQPair<const char*,int> maybeMimeType;
304 if ( !parseToken( scursor, send, maybeMimeType, false ) )
307 mMimeType = TQCString( maybeMimeType.first, maybeMimeType.second ).lower();
313 eatCFWS( scursor, send, isCRLF );
314 if ( scursor == send || *scursor != '/' ) return false;
316 eatCFWS( scursor, send, isCRLF );
317 if ( scursor == send ) return false;
319 TQPair<const char*,int> maybeSubType;
320 if ( !parseToken( scursor, send, maybeSubType, false ) )
323 mMimeSubType = TQCString( maybeSubType.first, maybeSubType.second ).lower();
329 eatCFWS( scursor, send, isCRLF );
330 if ( scursor == send ) return true;
332 if ( *scursor != ';' ) return false;
335 if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) )
347bool GCISTokenWithParameterList::parse( const char* & scursor,
348 const char * const send, bool isCRLF ) {
351 mParameterHash.clear();
357 eatCFWS( scursor, send, isCRLF );
358 if ( scursor == send ) return false;
360 TQPair<const char*,int> maybeToken;
361 if ( !parseToken( scursor, send, maybeToken, false ) )
364 mToken = TQCString( maybeToken.first, maybeToken.second ).lower();
370 eatCFWS( scursor, send, isCRLF );
371 if ( scursor == send ) return true;
373 if ( *scursor != ';' ) return false;
376 if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) )
388bool GIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) {
399 while ( scursor != send ) {
400 eatCFWS( scursor, send, isCRLF );
402 if ( scursor == send ) return true;
404 if ( *scursor == ',' ) { scursor++; continue; }
407 if ( !parseAngleAddr( scursor, send, maybeMsgId, isCRLF ) )
411 eatCFWS( scursor, send, isCRLF );
413 if ( scursor == send ) return true;
415 if ( *scursor == ',' ) scursor++;
426bool GSingleIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) {
428 if ( !GIdent::parse( scursor, send, isCRLF ) ) return false;
430 if ( mMsgIdList.count() > 1 ) {
431 KMIME_WARN << "more than one msg-id in header "
432 "allowing only a single one!" << endl;
447bool ReturnPath::parse( const char* & scursor, const char * const send, bool isCRLF ) {
449 eatCFWS( scursor, send, isCRLF );
450 if ( scursor == send ) return false;
452 const char * oldscursor = scursor;
454 Mailbox maybeMailbox;
455 if ( !parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) {
457 scursor = oldscursor;
458 if ( *scursor != '<' ) return false;
460 eatCFWS( scursor, send, isCRLF );
461 if ( scursor == send || *scursor != '>' ) return false;
465 AddrSpec emptyAddrSpec;
466 maybeMailbox.displayName = TQString();
467 maybeMailbox.addrSpec = emptyAddrSpec;
470 if ( !maybeMailbox.displayName.isEmpty() ) {
471 KMIME_WARN << "display-name \"" << maybeMailbox.displayName
472 << "\" in Return-Path!" << endl;
476 eatCFWS( scursor, send, isCRLF );
478 if ( scursor != send ) {
479 KMIME_WARN << "trailing garbage after angle-addr in Return-Path!" << endl;
491void Generic::setType( const char *type)
496 t_ype= new char[strlen( type)+1];
506#if !defined(KMIME_NEW_STYLE_CLASSTREE)
518 return ( typeIntro()+m_id );
532 return TQString::fromLatin1(m_id);
536void MessageID::generate( const TQCString &fqdn)
538 m_id= "<"+uniqueString()+ "@"+fqdn+ ">";
556 return ( typeIntro()+c_trlMsg );
570 return TQString::fromLatin1(c_trlMsg);
577#if !defined(KMIME_NEW_STYLE_CLASSTREE)
581 int pos1=0, pos2=0, type=0;
585 if(s.find( TQRegExp( "*@*(*)", false, true) )!=-1) type=2;
586 else if(s.find( TQRegExp( "*<*@*>", false, true) )!=-1) type=1;
587 else if(s.find( TQRegExp( "*@*", false, true) )!=-1) type=0;
603 n=s.mid(pos1, pos2-pos1).stripWhiteSpace();
605 pos2=s.find( '>', pos1);
607 e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace();
616 e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace();
618 pos2=s.find( ')', pos1);
620 n=s.mid(pos1, pos2-pos1).stripWhiteSpace();
638 if(incType && type()[0]!= '\0')
644 if (isUsAscii(n_ame)) {
645 TQCString tmp(n_ame.latin1());
646 addQuotes(tmp, false);
649 ret+=encodeRFC2047String(n_ame, e_ncCS, true);
651 if (!e_mail.isEmpty())
652 ret += " <"+e_mail+ ">";
661 int pos1=0, pos2=0, type=0;
664 e_ncCS=cachedCharset(cs);
667 if(s.find( TQRegExp( "*@*(*)", false, true) )!=-1) type=2;
668 else if(s.find( TQRegExp( "*<*@*>", false, true) )!=-1) type=1;
669 else if(s.find( TQRegExp( "*@*", false, true) )!=-1) type=0;
685 n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace();
687 pos2=s.find( '>', pos1);
689 e_mail=s.mid(pos1, pos2-pos1).latin1();
698 e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace().latin1();
700 pos2=s.find( ')', pos1);
702 n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace();
717 return TQString(e_mail);
720 if (!e_mail.isEmpty())
721 s += " <"+e_mail+ ">";
727TQCString AddressField::nameAs7Bit()
729 return encodeRFC2047String(n_ame, e_ncCS);
733void AddressField::setNameFrom7Bit( const TQCString &s)
744bool MailCopiesTo::isValid()
749 if ((n_ame == "nobody") ||
750 (n_ame == "never") ||
751 (n_ame == "poster") ||
759bool MailCopiesTo::alwaysCopy()
761 return (hasEmail() || (n_ame == "poster") || (n_ame == "always"));
765bool MailCopiesTo::neverCopy()
767 return ((n_ame == "nobody") || (n_ame == "never"));
779 t_ime=KRFCDate::parseDate(s);
786 return ( typeIntro()+KRFCDate::rfc2822DateString(t_ime) );
788 return TQCString(KRFCDate::rfc2822DateString(t_ime));
804TQDateTime Date::qdt()
814 TQDate today=TQDate::currentDate();
815 return ( qdt().date().daysTo(today) );
822#if !defined(KMIME_NEW_STYLE_CLASSTREE)
830 a_ddrList= new TQPtrList<AddressField>;
831 a_ddrList->setAutoDelete( true);
834 KTQCStringSplitter split;
836 bool splitOk=split.first();
841 a_ddrList->append( new AddressField(p_arent, split.string()) );
842 } while(split.next());
845 e_ncCS=cachedCharset(a_ddrList->first()->rfc2047Charset());
860 for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() )
873 a_ddrList= new TQPtrList<AddressField>;
874 a_ddrList->setAutoDelete( true);
877 TQStringList l=TQStringList::split( ",", s);
879 TQStringList::Iterator it=l.begin();
880 for(; it!=l.end(); ++it)
881 a_ddrList->append( new AddressField( p_arent, (*it), cs ));
883 e_ncCS=cachedCharset(cs);
897 for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() )
906 a_ddrList= new TQPtrList<AddressField>;
907 a_ddrList->setAutoDelete( true);
912 a_ddrList->append(add);
916void To::emails(TQStrList *l)
920 for ( AddressField *it=a_ddrList->first(); it != 0; it=a_ddrList->next() )
922 l->append( it->email() );
925void To::names(TQStringList *l)
929 for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() )
931 l->append( it->name() );
934void To::displayNames(TQStringList *l)
938 for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() )
939 l->append( it->asUnicodeString() );
951 e_ncCS=cachedCharset( "UTF-8");
958 return (typeIntro()+g_roups);
967 e_ncCS=cachedCharset( "UTF-8");
973 return TQString::fromUtf8(g_roups);
977TQCString Newsgroups::firstGroup()
980 if(!g_roups.isEmpty()) {
981 pos=g_roups.find( ',');
985 return g_roups.left(pos);
992TQStringList Newsgroups::getGroups()
994 TQStringList temp = TQStringList::split( ',', g_roups);
998 for (TQStringList::Iterator it = temp.begin(); it != temp.end(); ++it ) {
999 s = (*it).simplifyWhiteSpace();
1015 e_ncCS=cachedCharset(Latin1);
1025 return ( typeIntro()+num );
1034 e_ncCS=cachedCharset(Latin1);
1050#if !defined(KMIME_NEW_STYLE_CLASSTREE)
1056 e_ncCS=cachedCharset(Latin1);
1063 return ( typeIntro()+r_ef );
1072 e_ncCS=cachedCharset(Latin1);
1078 return TQString::fromLatin1(r_ef);
1082int References::count()
1085 unsigned int r_efLen=r_ef.length();
1086 char *dataPtr=r_ef.data();
1087 for( unsigned int i=0; i<r_efLen; i++) {
1088 if(dataPtr[i]== '<') cnt1++;
1089 else if(dataPtr[i]== '>') cnt2++;
1092 if(cnt1<cnt2) return cnt1;
1097TQCString References::first()
1104TQCString References::next()
1110 pos2=r_ef.findRev( '>', p_os);
1113 pos1=r_ef.findRev( '<', pos2);
1115 ret=r_ef.mid(pos1, pos2-pos1+1);
1124TQCString References::at( unsigned int i)
1130 while(pos1!=-1 && cnt < i+1) {
1132 pos1=r_ef.findRev( '<', pos2);
1137 pos2=r_ef.find( '>', pos1);
1139 ret=r_ef.mid(pos1, pos2-pos1+1);
1146void References::append( const TQCString &s)
1148 TQString temp=r_ef.data();
1151 TQStringList lst=TQStringList::split( ' ',temp);
1152 TQRegExp exp( "^<.+@.+>$");
1155 TQStringList::Iterator it = lst.begin();
1156 while (it != lst.end()) {
1157 if (-1==(*it).find(exp))
1158 it = lst.remove(it);
1163 if (lst.isEmpty()) {
1170 r_ef = temp.latin1();
1172 int insPos = r_ef.length();
1174 for ( int i=1;i<=3;i++) {
1175 if (!lst.isEmpty()) {
1177 r_ef.insert(insPos,(TQString( " %1").arg(temp)).latin1());
1183 while (!lst.isEmpty()) {
1185 if ((15+r_ef.length()+temp.length())<1000) {
1186 r_ef.insert(insPos,(TQString( " %1").arg(temp)).latin1());
1202 e_ncCS=cachedCharset(Latin1);
1209 return ( typeIntro()+u_agent );
1218 e_ncCS=cachedCharset(Latin1);
1224 return TQString::fromLatin1(u_agent);
1231#if !defined(KMIME_NEW_STYLE_CLASSTREE)
1236 int pos=s.find( ';');
1239 m_imeType=s.simplifyWhiteSpace();
1241 m_imeType=s.left(pos).simplifyWhiteSpace();
1242 p_arams=s.mid(pos, s.length()-pos).simplifyWhiteSpace();
1246 c_ategory=CCcontainer;
1250 e_ncCS=cachedCharset(Latin1);
1257 return (typeIntro()+m_imeType+p_arams);
1259 return (m_imeType+p_arams);
1275TQCString ContentType::mediaType()
1277 int pos=m_imeType.find( '/');
1281 return m_imeType.left(pos);
1285TQCString ContentType::subType()
1287 int pos=m_imeType.find( '/');
1291 return m_imeType.mid(pos, m_imeType.length()-pos);
1295void ContentType::setMimeType( const TQCString &s)
1301 c_ategory=CCcontainer;
1307bool ContentType::isMediatype( const char *s)
1309 return ( strncasecmp(m_imeType.data(), s, strlen(s)) );
1313bool ContentType::isSubtype( const char *s)
1315 char *c=strchr(m_imeType.data(), '/');
1317 if( (c==0) || (*(c+1)== '\0') )
1320 return ( strcasecmp(c+1, s)==0 );
1324bool ContentType::isText()
1326 return (strncasecmp(m_imeType.data(), "text", 4)==0);
1330bool ContentType::isPlainText()
1332 return (strcasecmp(m_imeType.data(), "text/plain")==0);
1336bool ContentType::isHTMLText()
1338 return (strcasecmp(m_imeType.data(), "text/html")==0);
1342bool ContentType::isImage()
1344 return (strncasecmp(m_imeType.data(), "image", 5)==0);
1348bool ContentType::isMultipart()
1350 return (strncasecmp(m_imeType.data(), "multipart", 9)==0);
1354bool ContentType::isPartial()
1356 return (strcasecmp(m_imeType.data(), "message/partial")==0);
1360TQCString ContentType::charset()
1362 TQCString ret=getParameter( "charset");
1363 if( ret.isEmpty() || forceCS() ) {
1370void ContentType::setCharset( const TQCString &s)
1372 setParameter( "charset", s);
1376TQCString ContentType::boundary()
1378 return getParameter( "boundary");
1382void ContentType::setBoundary( const TQCString &s)
1384 setParameter( "boundary", s, true);
1388TQString ContentType::name()
1390 const char *dummy=0;
1391 return ( decodeRFC2047String(getParameter( "name"), &dummy, defaultCS(), forceCS()) );
1395void ContentType::setName( const TQString &s, const TQCString &cs)
1400 TQCString tmp(s.latin1());
1401 addQuotes(tmp, true);
1402 setParameter( "name", tmp, false);
1405 setParameter( "name", encodeRFC2047String(s, cs), true);
1410TQCString ContentType::id()
1412 return (getParameter( "id"));
1416void ContentType::setId( const TQCString &s)
1418 setParameter( "id", s, true);
1422int ContentType::partialNumber()
1424 TQCString p=getParameter( "number");
1432int ContentType::partialCount()
1434 TQCString p=getParameter( "total");
1442void ContentType::setPartialParams( int total, int number)
1446 setParameter( "number", num);
1448 setParameter( "total", num);
1452TQCString ContentType::getParameter( const char *name)
1456 pos1=p_arams.find(name, 0, false);
1458 if( (pos2=p_arams.find( ';', pos1))==-1 )
1459 pos2=p_arams.length();
1460 pos1+=strlen(name)+1;
1461 ret=p_arams.mid(pos1, pos2-pos1);
1468void ContentType::setParameter( const TQCString &name, const TQCString &value, bool doubleQuotes)
1474 param=name+ "=\""+value+ "\"";
1476 param=name+ "="+value;
1478 pos1=p_arams.find(name.data(), 0, false);
1480 p_arams+= "; "+param;
1483 pos2=p_arams.find( ';', pos1);
1485 pos2=p_arams.length();
1486 p_arams.remove(pos1, pos2-pos1);
1487 p_arams.insert(pos1, param.data());
1497typedef struct { const char *s; int e; } encTableType;
1499static const encTableType encTable[] = { { "7Bit", CE7Bit },
1501 { "quoted-printable", CEquPr },
1502 { "base64", CEbase64 },
1503 { "x-uuencode", CEuuenc },
1504 { "binary", CEbinary },
1510 TQCString stripped(s.simplifyWhiteSpace());
1512 for( int i=0; encTable[i].s!=0; i++)
1513 if(strcasecmp(stripped.data(), encTable[i].s)==0) {
1514 c_te=(contentEncoding)encTable[i].e;
1517 d_ecoded=( c_te==CE7Bit || c_te==CE8Bit );
1519 e_ncCS=cachedCharset(Latin1);
1526 for( int i=0; encTable[i].s!=0; i++)
1527 if(c_te==encTable[i].e) {
1533 return ( typeIntro()+str );
1558 if(strncasecmp(s.data(), "attachment", 10)==0)
1560 else d_isp=CDinline;
1562 int pos=s.find( "filename=", 0, false);
1566 fn=s.mid(pos, s.length()-pos);
1576 if(d_isp==CDattachment)
1581 if(!f_ilename.isEmpty()) {
1582 if (isUsAscii(f_ilename)) {
1583 TQCString tmp(f_ilename.latin1());
1584 addQuotes(tmp, true);
1585 ret+= "; filename="+tmp;
1588 ret+= "; filename=\""+encodeRFC2047String(f_ilename, e_ncCS)+ "\"";
1593 return ( typeIntro()+ret );
1601 if(strncasecmp(s.latin1(), "attachment", 10)==0)
1603 else d_isp=CDinline;
1605 int pos=s.find( "filename=", 0, false);
1608 f_ilename=s.mid(pos, s.length()-pos);
1609 removeQuots(f_ilename);
1612 e_ncCS=cachedCharset(cs);
1619 if(d_isp==CDattachment)
1624 if(!f_ilename.isEmpty())
1625 ret+= "; filename=\""+f_ilename+ "\"";
|