kmime_headers.cpp
00001 /* 00002 kmime_headers.cpp 00003 00004 KMime, the KDE internet mail/usenet news message library. 00005 Copyright (c) 2001-2002 the KMime authors. 00006 See file AUTHORS for details 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 You should have received a copy of the GNU General Public License 00013 along with this program; if not, write to the Free Software Foundation, 00014 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US 00015 */ 00016 00017 00018 #include "kmime_headers.h" 00019 00020 #include "kmime_util.h" 00021 #include "kmime_content.h" 00022 #include "kmime_codecs.h" 00023 #include "kmime_header_parsing.h" 00024 #include "kmime_warning.h" 00025 00026 #include "kqcstringsplitter.h" 00027 00028 #include <tqtextcodec.h> 00029 #include <tqstring.h> 00030 #include <tqcstring.h> 00031 #include <tqstringlist.h> 00032 #include <tqvaluelist.h> 00033 00034 #include <kglobal.h> 00035 #include <kcharsets.h> 00036 #include <krfcdate.h> 00037 00038 #include <assert.h> 00039 00040 00041 using namespace KMime; 00042 using namespace KMime::Headers; 00043 using namespace KMime::Types; 00044 using namespace KMime::HeaderParsing; 00045 00046 namespace KMime { 00047 namespace Headers { 00048 //-----<Base>---------------------------------- 00049 00050 TQCString Base::rfc2047Charset() 00051 { 00052 if( (e_ncCS==0) || forceCS() ) 00053 return defaultCS(); 00054 else 00055 return TQCString(e_ncCS); 00056 } 00057 00058 00059 void Base::setRFC2047Charset(const TQCString &cs) 00060 { 00061 e_ncCS=cachedCharset(cs); 00062 } 00063 00064 00065 bool Base::forceCS() 00066 { 00067 return ( p_arent!=0 ? p_arent->forceDefaultCS() : false ); 00068 } 00069 00070 00071 TQCString Base::defaultCS() 00072 { 00073 return ( p_arent!=0 ? p_arent->defaultCharset() : Latin1 ); 00074 } 00075 00076 00077 //-----</Base>--------------------------------- 00078 00079 namespace Generics { 00080 00081 //-----<GUnstructured>------------------------- 00082 00083 void GUnstructured::from7BitString( const TQCString & str ) 00084 { 00085 d_ecoded = decodeRFC2047String( str, &e_ncCS, defaultCS(), forceCS() ); 00086 } 00087 00088 TQCString GUnstructured::as7BitString( bool withHeaderType ) 00089 { 00090 TQCString result; 00091 if ( withHeaderType ) 00092 result = typeIntro(); 00093 result += encodeRFC2047String( d_ecoded, e_ncCS ) ; 00094 00095 return result; 00096 } 00097 00098 void GUnstructured::fromUnicodeString( const TQString & str, 00099 const TQCString & suggestedCharset ) 00100 { 00101 d_ecoded = str; 00102 e_ncCS = cachedCharset( suggestedCharset ); 00103 } 00104 00105 TQString GUnstructured::asUnicodeString() 00106 { 00107 return d_ecoded; 00108 } 00109 00110 //-----</GUnstructured>------------------------- 00111 00112 00113 00114 //-----<GStructured>------------------------- 00115 00116 //-----</GStructured>------------------------- 00117 00118 00119 00120 00121 //-----<GAddress>------------------------- 00122 00123 00124 //-----</GAddress>------------------------- 00125 00126 00127 00128 //-----<MailboxList>------------------------- 00129 00130 bool MailboxList::parse( const char* & scursor, const char * const send, 00131 bool isCRLF ) { 00132 // examples: 00133 // from := "From:" mailbox-list CRLF 00134 // sender := "Sender:" mailbox CRLF 00135 00136 // parse an address-list: 00137 TQValueList<Address> maybeAddressList; 00138 if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) 00139 return false; 00140 00141 mMailboxList.clear(); 00142 00143 // extract the mailboxes and complain if there are groups: 00144 TQValueList<Address>::Iterator it; 00145 for ( it = maybeAddressList.begin(); it != maybeAddressList.end() ; ++it ) { 00146 if ( !(*it).displayName.isEmpty() ) { 00147 KMIME_WARN << "mailbox groups in header disallowing them! Name: \"" 00148 << (*it).displayName << "\"" << endl; 00149 } 00150 mMailboxList += (*it).mailboxList; 00151 } 00152 return true; 00153 } 00154 00155 //-----</MailboxList>------------------------- 00156 00157 00158 00159 //-----<SingleMailbox>------------------------- 00160 00161 bool SingleMailbox::parse( const char* & scursor, const char * const send, 00162 bool isCRLF ) { 00163 if ( !MailboxList::parse( scursor, send, isCRLF ) ) return false; 00164 00165 if ( mMailboxList.count() > 1 ) { 00166 KMIME_WARN << "multiple mailboxes in header allowing only a single one!" 00167 << endl; 00168 } 00169 return true; 00170 } 00171 00172 //-----</SingleMailbox>------------------------- 00173 00174 00175 00176 //-----<AddressList>------------------------- 00177 00178 bool AddressList::parse( const char* & scursor, const char * const send, 00179 bool isCRLF ) { 00180 00181 TQValueList<Address> maybeAddressList; 00182 if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) 00183 return false; 00184 00185 mAddressList = maybeAddressList; 00186 return true; 00187 } 00188 00189 //-----</AddressList>------------------------- 00190 00191 00192 00193 //-----<GToken>------------------------- 00194 00195 bool GToken::parse( const char* & scursor, const char * const send, 00196 bool isCRLF ) { 00197 00198 eatCFWS( scursor, send, isCRLF ); 00199 // must not be empty: 00200 if ( scursor == send ) return false; 00201 00202 TQPair<const char*,int> maybeToken; 00203 if ( !parseToken( scursor, send, maybeToken, false /* no 8bit chars */ ) ) 00204 return false; 00205 mToken = TQCString( maybeToken.first, maybeToken.second ); 00206 00207 // complain if trailing garbage is found: 00208 eatCFWS( scursor, send, isCRLF ); 00209 if ( scursor != send ) { 00210 KMIME_WARN << "trailing garbage after token in header allowing " 00211 "only a single token!" << endl; 00212 } 00213 return true; 00214 } 00215 00216 //-----</GToken>------------------------- 00217 00218 00219 00220 //-----<GPhraseList>------------------------- 00221 00222 bool GPhraseList::parse( const char* & scursor, const char * const send, 00223 bool isCRLF ) { 00224 00225 mPhraseList.clear(); 00226 00227 while ( scursor != send ) { 00228 eatCFWS( scursor, send, isCRLF ); 00229 // empty entry ending the list: OK. 00230 if ( scursor == send ) return true; 00231 // empty entry: ignore. 00232 if ( *scursor != ',' ) { scursor++; continue; } 00233 00234 TQString maybePhrase; 00235 if ( !parsePhrase( scursor, send, maybePhrase, isCRLF ) ) 00236 return false; 00237 mPhraseList.append( maybePhrase ); 00238 00239 eatCFWS( scursor, send, isCRLF ); 00240 // non-empty entry ending the list: OK. 00241 if ( scursor == send ) return true; 00242 // comma separating the phrases: eat. 00243 if ( *scursor != ',' ) scursor++; 00244 } 00245 return true; 00246 } 00247 00248 //-----</GPhraseList>------------------------- 00249 00250 00251 00252 //-----<GDotAtom>------------------------- 00253 00254 bool GDotAtom::parse( const char* & scursor, const char * const send, 00255 bool isCRLF ) { 00256 00257 TQString maybeDotAtom; 00258 if ( !parseDotAtom( scursor, send, maybeDotAtom, isCRLF ) ) 00259 return false; 00260 00261 mDotAtom = maybeDotAtom; 00262 00263 eatCFWS( scursor, send, isCRLF ); 00264 if ( scursor != send ) { 00265 KMIME_WARN << "trailing garbage after dot-atom in header allowing " 00266 "only a single dot-atom!" << endl; 00267 } 00268 return true; 00269 } 00270 00271 //-----</GDotAtom>------------------------- 00272 00273 00274 00275 //-----<GParametrized>------------------------- 00276 00277 //-----</GParametrized>------------------------- 00278 00279 00280 00281 00282 //-----</GContentType>------------------------- 00283 00284 bool GContentType::parse( const char* & scursor, const char * const send, 00285 bool isCRLF ) { 00286 00287 // content-type: type "/" subtype *(";" parameter) 00288 00289 mMimeType = 0; 00290 mMimeSubType = 0; 00291 mParameterHash.clear(); 00292 00293 eatCFWS( scursor, send, isCRLF ); 00294 if ( scursor == send ) { 00295 // empty header 00296 return false; 00297 } 00298 00299 // 00300 // type 00301 // 00302 00303 TQPair<const char*,int> maybeMimeType; 00304 if ( !parseToken( scursor, send, maybeMimeType, false /* no 8Bit */ ) ) 00305 return false; 00306 00307 mMimeType = TQCString( maybeMimeType.first, maybeMimeType.second ).lower(); 00308 00309 // 00310 // subtype 00311 // 00312 00313 eatCFWS( scursor, send, isCRLF ); 00314 if ( scursor == send || *scursor != '/' ) return false; 00315 scursor++; 00316 eatCFWS( scursor, send, isCRLF ); 00317 if ( scursor == send ) return false; 00318 00319 TQPair<const char*,int> maybeSubType; 00320 if ( !parseToken( scursor, send, maybeSubType, false /* no 8bit */ ) ) 00321 return false; 00322 00323 mMimeSubType = TQCString( maybeSubType.first, maybeSubType.second ).lower(); 00324 00325 // 00326 // parameter list 00327 // 00328 00329 eatCFWS( scursor, send, isCRLF ); 00330 if ( scursor == send ) return true; // no parameters 00331 00332 if ( *scursor != ';' ) return false; 00333 scursor++; 00334 00335 if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) ) 00336 return false; 00337 00338 return true; 00339 } 00340 00341 //-----</GContentType>------------------------- 00342 00343 00344 00345 //-----<GTokenWithParameterList>------------------------- 00346 00347 bool GCISTokenWithParameterList::parse( const char* & scursor, 00348 const char * const send, bool isCRLF ) { 00349 00350 mToken = 0; 00351 mParameterHash.clear(); 00352 00353 // 00354 // token 00355 // 00356 00357 eatCFWS( scursor, send, isCRLF ); 00358 if ( scursor == send ) return false; 00359 00360 TQPair<const char*,int> maybeToken; 00361 if ( !parseToken( scursor, send, maybeToken, false /* no 8Bit */ ) ) 00362 return false; 00363 00364 mToken = TQCString( maybeToken.first, maybeToken.second ).lower(); 00365 00366 // 00367 // parameter list 00368 // 00369 00370 eatCFWS( scursor, send, isCRLF ); 00371 if ( scursor == send ) return true; // no parameters 00372 00373 if ( *scursor != ';' ) return false; 00374 scursor++; 00375 00376 if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) ) 00377 return false; 00378 00379 return true; 00380 } 00381 00382 //-----</GTokenWithParameterList>------------------------- 00383 00384 00385 00386 //-----<GIdent>------------------------- 00387 00388 bool GIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) { 00389 00390 // msg-id := "<" id-left "@" id-right ">" 00391 // id-left := dot-atom-text / no-fold-quote / local-part 00392 // id-right := dot-atom-text / no-fold-literal / domain 00393 // 00394 // equivalent to: 00395 // msg-id := angle-addr 00396 00397 mMsgIdList.clear(); 00398 00399 while ( scursor != send ) { 00400 eatCFWS( scursor, send, isCRLF ); 00401 // empty entry ending the list: OK. 00402 if ( scursor == send ) return true; 00403 // empty entry: ignore. 00404 if ( *scursor == ',' ) { scursor++; continue; } 00405 00406 AddrSpec maybeMsgId; 00407 if ( !parseAngleAddr( scursor, send, maybeMsgId, isCRLF ) ) 00408 return false; 00409 mMsgIdList.append( maybeMsgId ); 00410 00411 eatCFWS( scursor, send, isCRLF ); 00412 // header end ending the list: OK. 00413 if ( scursor == send ) return true; 00414 // regular item separator: eat it. 00415 if ( *scursor == ',' ) scursor++; 00416 } 00417 return true; 00418 } 00419 00420 //-----</GIdent>------------------------- 00421 00422 00423 00424 //-----<GSingleIdent>------------------------- 00425 00426 bool GSingleIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) { 00427 00428 if ( !GIdent::parse( scursor, send, isCRLF ) ) return false; 00429 00430 if ( mMsgIdList.count() > 1 ) { 00431 KMIME_WARN << "more than one msg-id in header " 00432 "allowing only a single one!" << endl; 00433 } 00434 return true; 00435 } 00436 00437 //-----</GSingleIdent>------------------------- 00438 00439 00440 00441 00442 } // namespace Generics 00443 00444 00445 //-----<ReturnPath>------------------------- 00446 00447 bool ReturnPath::parse( const char* & scursor, const char * const send, bool isCRLF ) { 00448 00449 eatCFWS( scursor, send, isCRLF ); 00450 if ( scursor == send ) return false; 00451 00452 const char * oldscursor = scursor; 00453 00454 Mailbox maybeMailbox; 00455 if ( !parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) { 00456 // mailbox parsing failed, but check for empty brackets: 00457 scursor = oldscursor; 00458 if ( *scursor != '<' ) return false; 00459 scursor++; 00460 eatCFWS( scursor, send, isCRLF ); 00461 if ( scursor == send || *scursor != '>' ) return false; 00462 scursor++; 00463 00464 // prepare a Null mailbox: 00465 AddrSpec emptyAddrSpec; 00466 maybeMailbox.displayName = TQString(); 00467 maybeMailbox.addrSpec = emptyAddrSpec; 00468 } else 00469 // check that there was no display-name: 00470 if ( !maybeMailbox.displayName.isEmpty() ) { 00471 KMIME_WARN << "display-name \"" << maybeMailbox.displayName 00472 << "\" in Return-Path!" << endl; 00473 } 00474 00475 // see if that was all: 00476 eatCFWS( scursor, send, isCRLF ); 00477 // and warn if it wasn't: 00478 if ( scursor != send ) { 00479 KMIME_WARN << "trailing garbage after angle-addr in Return-Path!" << endl; 00480 } 00481 return true; 00482 } 00483 00484 //-----</ReturnPath>------------------------- 00485 00486 00487 00488 00489 //-----<Generic>------------------------------- 00490 00491 void Generic::setType(const char *type) 00492 { 00493 if(t_ype) 00494 delete[] t_ype; 00495 if(type) { 00496 t_ype=new char[strlen(type)+1]; 00497 strcpy(t_ype, type); 00498 } 00499 else 00500 t_ype=0; 00501 } 00502 00503 //-----<Generic>------------------------------- 00504 00505 00506 #if !defined(KMIME_NEW_STYLE_CLASSTREE) 00507 //-----<MessageID>----------------------------- 00508 00509 void MessageID::from7BitString(const TQCString &s) 00510 { 00511 m_id=s; 00512 } 00513 00514 00515 TQCString MessageID::as7BitString(bool incType) 00516 { 00517 if(incType) 00518 return ( typeIntro()+m_id ); 00519 else 00520 return m_id; 00521 } 00522 00523 00524 void MessageID::fromUnicodeString(const TQString &s, const TQCString&) 00525 { 00526 m_id=s.latin1(); //Message-Ids can only contain us-ascii chars 00527 } 00528 00529 00530 TQString MessageID::asUnicodeString() 00531 { 00532 return TQString::fromLatin1(m_id); 00533 } 00534 00535 00536 void MessageID::generate(const TQCString &fqdn) 00537 { 00538 m_id="<"+uniqueString()+"@"+fqdn+">"; 00539 } 00540 00541 //-----</MessageID>---------------------------- 00542 #endif 00543 00544 00545 //-----<Control>------------------------------- 00546 00547 void Control::from7BitString(const TQCString &s) 00548 { 00549 c_trlMsg=s; 00550 } 00551 00552 00553 TQCString Control::as7BitString(bool incType) 00554 { 00555 if(incType) 00556 return ( typeIntro()+c_trlMsg ); 00557 else 00558 return c_trlMsg; 00559 } 00560 00561 00562 void Control::fromUnicodeString(const TQString &s, const TQCString&) 00563 { 00564 c_trlMsg=s.latin1(); 00565 } 00566 00567 00568 TQString Control::asUnicodeString() 00569 { 00570 return TQString::fromLatin1(c_trlMsg); 00571 } 00572 00573 //-----</Control>------------------------------ 00574 00575 00576 00577 #if !defined(KMIME_NEW_STYLE_CLASSTREE) 00578 //-----<AddressField>-------------------------- 00579 void AddressField::from7BitString(const TQCString &s) 00580 { 00581 int pos1=0, pos2=0, type=0; 00582 TQCString n; 00583 00584 //so what do we have here ? 00585 if(s.find( TQRegExp("*@*(*)", false, true) )!=-1) type=2; // From: foo@bar.com (John Doe) 00586 else if(s.find( TQRegExp("*<*@*>", false, true) )!=-1) type=1; // From: John Doe <foo@bar.com> 00587 else if(s.find( TQRegExp("*@*", false, true) )!=-1) type=0; // From: foo@bar.com 00588 else { //broken From header => just decode it 00589 n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS()); 00590 return; 00591 } 00592 00593 switch(type) { 00594 00595 case 0: 00596 e_mail=s.copy(); 00597 break; 00598 00599 case 1: 00600 pos1=0; 00601 pos2=s.find('<'); 00602 if(pos2!=-1) { 00603 n=s.mid(pos1, pos2-pos1).stripWhiteSpace(); 00604 pos1=pos2+1; 00605 pos2=s.find('>', pos1); 00606 if(pos2!=-1) 00607 e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace(); 00608 } 00609 else return; 00610 break; 00611 00612 case 2: 00613 pos1=0; 00614 pos2=s.find('('); 00615 if(pos2!=-1) { 00616 e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace(); 00617 pos1=pos2+1; 00618 pos2=s.find(')', pos1); 00619 if(pos2!=-1) 00620 n=s.mid(pos1, pos2-pos1).stripWhiteSpace(); 00621 } 00622 break; 00623 00624 default: break; 00625 } 00626 00627 if(!n.isEmpty()) { 00628 removeQuots(n); 00629 n_ame=decodeRFC2047String(n, &e_ncCS, defaultCS(), forceCS()); 00630 } 00631 } 00632 00633 00634 TQCString AddressField::as7BitString(bool incType) 00635 { 00636 TQCString ret; 00637 00638 if(incType && type()[0]!='\0') 00639 ret=typeIntro(); 00640 00641 if(n_ame.isEmpty()) 00642 ret+=e_mail; 00643 else { 00644 if (isUsAscii(n_ame)) { 00645 TQCString tmp(n_ame.latin1()); 00646 addQuotes(tmp, false); 00647 ret+=tmp; 00648 } else { 00649 ret+=encodeRFC2047String(n_ame, e_ncCS, true); 00650 } 00651 if (!e_mail.isEmpty()) 00652 ret += " <"+e_mail+">"; 00653 } 00654 00655 return ret; 00656 } 00657 00658 00659 void AddressField::fromUnicodeString(const TQString &s, const TQCString &cs) 00660 { 00661 int pos1=0, pos2=0, type=0; 00662 TQCString n; 00663 00664 e_ncCS=cachedCharset(cs); 00665 00666 //so what do we have here ? 00667 if(s.find( TQRegExp("*@*(*)", false, true) )!=-1) type=2; // From: foo@bar.com (John Doe) 00668 else if(s.find( TQRegExp("*<*@*>", false, true) )!=-1) type=1; // From: John Doe <foo@bar.com> 00669 else if(s.find( TQRegExp("*@*", false, true) )!=-1) type=0; // From: foo@bar.com 00670 else { //broken From header => just copy it 00671 n_ame=s; 00672 return; 00673 } 00674 00675 switch(type) { 00676 00677 case 0: 00678 e_mail=s.latin1(); 00679 break; 00680 00681 case 1: 00682 pos1=0; 00683 pos2=s.find('<'); 00684 if(pos2!=-1) { 00685 n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace(); 00686 pos1=pos2+1; 00687 pos2=s.find('>', pos1); 00688 if(pos2!=-1) 00689 e_mail=s.mid(pos1, pos2-pos1).latin1(); 00690 } 00691 else return; 00692 break; 00693 00694 case 2: 00695 pos1=0; 00696 pos2=s.find('('); 00697 if(pos2!=-1) { 00698 e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace().latin1(); 00699 pos1=pos2+1; 00700 pos2=s.find(')', pos1); 00701 if(pos2!=-1) 00702 n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace(); 00703 } 00704 break; 00705 00706 default: break; 00707 } 00708 00709 if(!n_ame.isEmpty()) 00710 removeQuots(n_ame); 00711 } 00712 00713 00714 TQString AddressField::asUnicodeString() 00715 { 00716 if(n_ame.isEmpty()) 00717 return TQString(e_mail); 00718 else { 00719 TQString s = n_ame; 00720 if (!e_mail.isEmpty()) 00721 s += " <"+e_mail+">"; 00722 return s; 00723 } 00724 } 00725 00726 00727 TQCString AddressField::nameAs7Bit() 00728 { 00729 return encodeRFC2047String(n_ame, e_ncCS); 00730 } 00731 00732 00733 void AddressField::setNameFrom7Bit(const TQCString &s) 00734 { 00735 n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS()); 00736 } 00737 00738 //-----</AddressField>------------------------- 00739 #endif 00740 00741 00742 //-----<MailCopiesTo>-------------------------- 00743 00744 bool MailCopiesTo::isValid() 00745 { 00746 if (hasEmail()) 00747 return true; 00748 00749 if ((n_ame == "nobody") || 00750 (n_ame == "never") || 00751 (n_ame == "poster") || 00752 (n_ame == "always")) 00753 return true; 00754 else 00755 return false; 00756 } 00757 00758 00759 bool MailCopiesTo::alwaysCopy() 00760 { 00761 return (hasEmail() || (n_ame == "poster") || (n_ame == "always")); 00762 } 00763 00764 00765 bool MailCopiesTo::neverCopy() 00766 { 00767 return ((n_ame == "nobody") || (n_ame == "never")); 00768 } 00769 00770 //-----</MailCopiesTo>------------------------- 00771 00772 00773 00774 00775 //-----<Date>---------------------------------- 00776 00777 void Date::from7BitString(const TQCString &s) 00778 { 00779 t_ime=KRFCDate::parseDate(s); 00780 } 00781 00782 00783 TQCString Date::as7BitString(bool incType) 00784 { 00785 if(incType) 00786 return ( typeIntro()+KRFCDate::rfc2822DateString(t_ime) ); 00787 else 00788 return TQCString(KRFCDate::rfc2822DateString(t_ime)); 00789 } 00790 00791 00792 void Date::fromUnicodeString(const TQString &s, const TQCString&) 00793 { 00794 from7BitString( TQCString(s.latin1()) ); 00795 } 00796 00797 00798 TQString Date::asUnicodeString() 00799 { 00800 return TQString::fromLatin1(as7BitString(false)); 00801 } 00802 00803 00804 TQDateTime Date::qdt() 00805 { 00806 TQDateTime dt; 00807 dt.setTime_t(t_ime); 00808 return dt; 00809 } 00810 00811 00812 int Date::ageInDays() 00813 { 00814 TQDate today=TQDate::currentDate(); 00815 return ( qdt().date().daysTo(today) ); 00816 } 00817 00818 //-----</Date>--------------------------------- 00819 00820 00821 00822 #if !defined(KMIME_NEW_STYLE_CLASSTREE) 00823 //-----<To>------------------------------------ 00824 00825 void To::from7BitString(const TQCString &s) 00826 { 00827 if(a_ddrList) 00828 a_ddrList->clear(); 00829 else { 00830 a_ddrList=new TQPtrList<AddressField>; 00831 a_ddrList->setAutoDelete(true); 00832 } 00833 00834 KTQCStringSplitter split; 00835 split.init(s, ","); 00836 bool splitOk=split.first(); 00837 if(!splitOk) 00838 a_ddrList->append( new AddressField(p_arent, s )); 00839 else { 00840 do { 00841 a_ddrList->append( new AddressField(p_arent, split.string()) ); 00842 } while(split.next()); 00843 } 00844 00845 e_ncCS=cachedCharset(a_ddrList->first()->rfc2047Charset()); 00846 } 00847 00848 00849 TQCString To::as7BitString(bool incType) 00850 { 00851 TQCString ret; 00852 00853 if(incType) 00854 ret+=typeIntro(); 00855 00856 if (a_ddrList) { 00857 AddressField *it=a_ddrList->first(); 00858 if (it) 00859 ret+=it->as7BitString(false); 00860 for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() ) 00861 ret+=","+it->as7BitString(false); 00862 } 00863 00864 return ret; 00865 } 00866 00867 00868 void To::fromUnicodeString(const TQString &s, const TQCString &cs) 00869 { 00870 if(a_ddrList) 00871 a_ddrList->clear(); 00872 else { 00873 a_ddrList=new TQPtrList<AddressField>; 00874 a_ddrList->setAutoDelete(true); 00875 } 00876 00877 TQStringList l=TQStringList::split(",", s); 00878 00879 TQStringList::Iterator it=l.begin(); 00880 for(; it!=l.end(); ++it) 00881 a_ddrList->append(new AddressField( p_arent, (*it), cs )); 00882 00883 e_ncCS=cachedCharset(cs); 00884 } 00885 00886 00887 TQString To::asUnicodeString() 00888 { 00889 if(!a_ddrList) 00890 return TQString(); 00891 00892 TQString ret; 00893 AddressField *it=a_ddrList->first(); 00894 00895 if (it) 00896 ret+=it->asUnicodeString(); 00897 for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() ) 00898 ret+=","+it->asUnicodeString(); 00899 return ret; 00900 } 00901 00902 00903 void To::addAddress(const AddressField &a) 00904 { 00905 if(!a_ddrList) { 00906 a_ddrList=new TQPtrList<AddressField>; 00907 a_ddrList->setAutoDelete(true); 00908 } 00909 00910 AddressField *add=new AddressField(a); 00911 add->setParent(p_arent); 00912 a_ddrList->append(add); 00913 } 00914 00915 00916 void To::emails(TQStrList *l) 00917 { 00918 l->clear(); 00919 00920 for (AddressField *it=a_ddrList->first(); it != 0; it=a_ddrList->next() ) 00921 if( it->hasEmail() ) 00922 l->append( it->email() ); 00923 } 00924 00925 void To::names(TQStringList *l) 00926 { 00927 l->clear(); 00928 00929 for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() ) 00930 if( it->hasName() ) 00931 l->append( it->name() ); 00932 } 00933 00934 void To::displayNames(TQStringList *l) 00935 { 00936 l->clear(); 00937 00938 for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() ) 00939 l->append( it->asUnicodeString() ); 00940 } 00941 00942 //-----</To>----------------------------------- 00943 #endif 00944 00945 00946 //-----<Newsgroups>---------------------------- 00947 00948 void Newsgroups::from7BitString(const TQCString &s) 00949 { 00950 g_roups=s; 00951 e_ncCS=cachedCharset("UTF-8"); 00952 } 00953 00954 00955 TQCString Newsgroups::as7BitString(bool incType) 00956 { 00957 if(incType) 00958 return (typeIntro()+g_roups); 00959 else 00960 return g_roups; 00961 } 00962 00963 00964 void Newsgroups::fromUnicodeString(const TQString &s, const TQCString&) 00965 { 00966 g_roups=s.utf8(); 00967 e_ncCS=cachedCharset("UTF-8"); 00968 } 00969 00970 00971 TQString Newsgroups::asUnicodeString() 00972 { 00973 return TQString::fromUtf8(g_roups); 00974 } 00975 00976 00977 TQCString Newsgroups::firstGroup() 00978 { 00979 int pos=0; 00980 if(!g_roups.isEmpty()) { 00981 pos=g_roups.find(','); 00982 if(pos==-1) 00983 return g_roups; 00984 else 00985 return g_roups.left(pos); 00986 } 00987 else 00988 return TQCString(); 00989 } 00990 00991 00992 TQStringList Newsgroups::getGroups() 00993 { 00994 TQStringList temp = TQStringList::split(',', g_roups); 00995 TQStringList ret; 00996 TQString s; 00997 00998 for (TQStringList::Iterator it = temp.begin(); it != temp.end(); ++it ) { 00999 s = (*it).simplifyWhiteSpace(); 01000 ret.append(s); 01001 } 01002 01003 return ret; 01004 } 01005 01006 //-----</Newsgroups>--------------------------- 01007 01008 01009 01010 //-----<Lines>--------------------------------- 01011 01012 void Lines::from7BitString(const TQCString &s) 01013 { 01014 l_ines=s.toInt(); 01015 e_ncCS=cachedCharset(Latin1); 01016 } 01017 01018 01019 TQCString Lines::as7BitString(bool incType) 01020 { 01021 TQCString num; 01022 num.setNum(l_ines); 01023 01024 if(incType) 01025 return ( typeIntro()+num ); 01026 else 01027 return num; 01028 } 01029 01030 01031 void Lines::fromUnicodeString(const TQString &s, const TQCString&) 01032 { 01033 l_ines=s.toInt(); 01034 e_ncCS=cachedCharset(Latin1); 01035 } 01036 01037 01038 TQString Lines::asUnicodeString() 01039 { 01040 TQString num; 01041 num.setNum(l_ines); 01042 01043 return num; 01044 } 01045 01046 //-----</Lines>-------------------------------- 01047 01048 01049 01050 #if !defined(KMIME_NEW_STYLE_CLASSTREE) 01051 //-----<References>---------------------------- 01052 01053 void References::from7BitString(const TQCString &s) 01054 { 01055 r_ef=s; 01056 e_ncCS=cachedCharset(Latin1); 01057 } 01058 01059 01060 TQCString References::as7BitString(bool incType) 01061 { 01062 if(incType) 01063 return ( typeIntro()+r_ef ); 01064 else 01065 return r_ef; 01066 } 01067 01068 01069 void References::fromUnicodeString(const TQString &s, const TQCString&) 01070 { 01071 r_ef=s.latin1(); 01072 e_ncCS=cachedCharset(Latin1); 01073 } 01074 01075 01076 TQString References::asUnicodeString() 01077 { 01078 return TQString::fromLatin1(r_ef); 01079 } 01080 01081 01082 int References::count() 01083 { 01084 int cnt1=0, cnt2=0; 01085 unsigned int r_efLen=r_ef.length(); 01086 char *dataPtr=r_ef.data(); 01087 for(unsigned int i=0; i<r_efLen; i++) { 01088 if(dataPtr[i]=='<') cnt1++; 01089 else if(dataPtr[i]=='>') cnt2++; 01090 } 01091 01092 if(cnt1<cnt2) return cnt1; 01093 else return cnt2; 01094 } 01095 01096 01097 TQCString References::first() 01098 { 01099 p_os=-1; 01100 return next(); 01101 } 01102 01103 01104 TQCString References::next() 01105 { 01106 int pos1=0, pos2=0; 01107 TQCString ret; 01108 01109 if(p_os!=0) { 01110 pos2=r_ef.findRev('>', p_os); 01111 p_os=0; 01112 if(pos2!=-1) { 01113 pos1=r_ef.findRev('<', pos2); 01114 if(pos1!=-1) { 01115 ret=r_ef.mid(pos1, pos2-pos1+1); 01116 p_os=pos1; 01117 } 01118 } 01119 } 01120 return ret; 01121 } 01122 01123 01124 TQCString References::at(unsigned int i) 01125 { 01126 TQCString ret; 01127 int pos1=0, pos2=0; 01128 unsigned int cnt=0; 01129 01130 while(pos1!=-1 && cnt < i+1) { 01131 pos2=pos1-1; 01132 pos1=r_ef.findRev('<', pos2); 01133 cnt++; 01134 } 01135 01136 if(pos1!=-1) { 01137 pos2=r_ef.find('>', pos1); 01138 if(pos2!=-1) 01139 ret=r_ef.mid(pos1, pos2-pos1+1); 01140 } 01141 01142 return ret; 01143 } 01144 01145 01146 void References::append(const TQCString &s) 01147 { 01148 TQString temp=r_ef.data(); 01149 temp += " "; 01150 temp += s.data(); 01151 TQStringList lst=TQStringList::split(' ',temp); 01152 TQRegExp exp("^<.+@.+>$"); 01153 01154 // remove bogus references 01155 TQStringList::Iterator it = lst.begin(); 01156 while (it != lst.end()) { 01157 if (-1==(*it).find(exp)) 01158 it = lst.remove(it); 01159 else 01160 it++; 01161 } 01162 01163 if (lst.isEmpty()) { 01164 r_ef = s.copy(); // shouldn't happen... 01165 return; 01166 } else 01167 r_ef = ""; 01168 01169 temp = lst.first(); // include the first id 01170 r_ef = temp.latin1(); 01171 lst.remove(temp); // avoids duplicates 01172 int insPos = r_ef.length(); 01173 01174 for (int i=1;i<=3;i++) { // include the last three ids 01175 if (!lst.isEmpty()) { 01176 temp = lst.last(); 01177 r_ef.insert(insPos,(TQString(" %1").arg(temp)).latin1()); 01178 lst.remove(temp); 01179 } else 01180 break; 01181 } 01182 01183 while (!lst.isEmpty()) { // now insert the rest, up to 1000 characters 01184 temp = lst.last(); 01185 if ((15+r_ef.length()+temp.length())<1000) { 01186 r_ef.insert(insPos,(TQString(" %1").arg(temp)).latin1()); 01187 lst.remove(temp); 01188 } else 01189 return; 01190 } 01191 } 01192 01193 //-----</References>--------------------------- 01194 #endif 01195 01196 01197 //-----<UserAgent>----------------------------- 01198 01199 void UserAgent::from7BitString(const TQCString &s) 01200 { 01201 u_agent=s; 01202 e_ncCS=cachedCharset(Latin1); 01203 } 01204 01205 01206 TQCString UserAgent::as7BitString(bool incType) 01207 { 01208 if(incType) 01209 return ( typeIntro()+u_agent ); 01210 else 01211 return u_agent; 01212 } 01213 01214 01215 void UserAgent::fromUnicodeString(const TQString &s, const TQCString&) 01216 { 01217 u_agent=s.latin1(); 01218 e_ncCS=cachedCharset(Latin1); 01219 } 01220 01221 01222 TQString UserAgent::asUnicodeString() 01223 { 01224 return TQString::fromLatin1(u_agent); 01225 } 01226 01227 //-----</UserAgent>---------------------------- 01228 01229 01230 01231 #if !defined(KMIME_NEW_STYLE_CLASSTREE) 01232 //-----<Content-Type>-------------------------- 01233 01234 void ContentType::from7BitString(const TQCString &s) 01235 { 01236 int pos=s.find(';'); 01237 01238 if(pos==-1) 01239 m_imeType=s.simplifyWhiteSpace(); 01240 else { 01241 m_imeType=s.left(pos).simplifyWhiteSpace(); 01242 p_arams=s.mid(pos, s.length()-pos).simplifyWhiteSpace(); 01243 } 01244 01245 if(isMultipart()) 01246 c_ategory=CCcontainer; 01247 else 01248 c_ategory=CCsingle; 01249 01250 e_ncCS=cachedCharset(Latin1); 01251 } 01252 01253 01254 TQCString ContentType::as7BitString(bool incType) 01255 { 01256 if(incType) 01257 return (typeIntro()+m_imeType+p_arams); 01258 else 01259 return (m_imeType+p_arams); 01260 } 01261 01262 01263 void ContentType::fromUnicodeString(const TQString &s, const TQCString&) 01264 { 01265 from7BitString( TQCString(s.latin1()) ); 01266 } 01267 01268 01269 TQString ContentType::asUnicodeString() 01270 { 01271 return TQString::fromLatin1(as7BitString(false)); 01272 } 01273 01274 01275 TQCString ContentType::mediaType() 01276 { 01277 int pos=m_imeType.find('/'); 01278 if(pos==-1) 01279 return m_imeType; 01280 else 01281 return m_imeType.left(pos); 01282 } 01283 01284 01285 TQCString ContentType::subType() 01286 { 01287 int pos=m_imeType.find('/'); 01288 if(pos==-1) 01289 return TQCString(); 01290 else 01291 return m_imeType.mid(pos, m_imeType.length()-pos); 01292 } 01293 01294 01295 void ContentType::setMimeType(const TQCString &s) 01296 { 01297 p_arams.resize(0); 01298 m_imeType=s; 01299 01300 if(isMultipart()) 01301 c_ategory=CCcontainer; 01302 else 01303 c_ategory=CCsingle; 01304 } 01305 01306 01307 bool ContentType::isMediatype(const char *s) 01308 { 01309 return ( strncasecmp(m_imeType.data(), s, strlen(s)) ); 01310 } 01311 01312 01313 bool ContentType::isSubtype(const char *s) 01314 { 01315 char *c=strchr(m_imeType.data(), '/'); 01316 01317 if( (c==0) || (*(c+1)=='\0') ) 01318 return false; 01319 else 01320 return ( strcasecmp(c+1, s)==0 ); 01321 } 01322 01323 01324 bool ContentType::isText() 01325 { 01326 return (strncasecmp(m_imeType.data(), "text", 4)==0); 01327 } 01328 01329 01330 bool ContentType::isPlainText() 01331 { 01332 return (strcasecmp(m_imeType.data(), "text/plain")==0); 01333 } 01334 01335 01336 bool ContentType::isHTMLText() 01337 { 01338 return (strcasecmp(m_imeType.data(), "text/html")==0); 01339 } 01340 01341 01342 bool ContentType::isImage() 01343 { 01344 return (strncasecmp(m_imeType.data(), "image", 5)==0); 01345 } 01346 01347 01348 bool ContentType::isMultipart() 01349 { 01350 return (strncasecmp(m_imeType.data(), "multipart", 9)==0); 01351 } 01352 01353 01354 bool ContentType::isPartial() 01355 { 01356 return (strcasecmp(m_imeType.data(), "message/partial")==0); 01357 } 01358 01359 01360 TQCString ContentType::charset() 01361 { 01362 TQCString ret=getParameter("charset"); 01363 if( ret.isEmpty() || forceCS() ) { //we return the default-charset if necessary 01364 ret=defaultCS(); 01365 } 01366 return ret; 01367 } 01368 01369 01370 void ContentType::setCharset(const TQCString &s) 01371 { 01372 setParameter("charset", s); 01373 } 01374 01375 01376 TQCString ContentType::boundary() 01377 { 01378 return getParameter("boundary"); 01379 } 01380 01381 01382 void ContentType::setBoundary(const TQCString &s) 01383 { 01384 setParameter("boundary", s, true); 01385 } 01386 01387 01388 TQString ContentType::name() 01389 { 01390 const char *dummy=0; 01391 return ( decodeRFC2047String(getParameter("name"), &dummy, defaultCS(), forceCS()) ); 01392 } 01393 01394 01395 void ContentType::setName(const TQString &s, const TQCString &cs) 01396 { 01397 e_ncCS=cs; 01398 01399 if (isUsAscii(s)) { 01400 TQCString tmp(s.latin1()); 01401 addQuotes(tmp, true); 01402 setParameter("name", tmp, false); 01403 } else { 01404 // FIXME: encoded words can't be enclosed in quotes!! 01405 setParameter("name", encodeRFC2047String(s, cs), true); 01406 } 01407 } 01408 01409 01410 TQCString ContentType::id() 01411 { 01412 return (getParameter("id")); 01413 } 01414 01415 01416 void ContentType::setId(const TQCString &s) 01417 { 01418 setParameter("id", s, true); 01419 } 01420 01421 01422 int ContentType::partialNumber() 01423 { 01424 TQCString p=getParameter("number"); 01425 if(!p.isEmpty()) 01426 return p.toInt(); 01427 else 01428 return -1; 01429 } 01430 01431 01432 int ContentType::partialCount() 01433 { 01434 TQCString p=getParameter("total"); 01435 if(!p.isEmpty()) 01436 return p.toInt(); 01437 else 01438 return -1; 01439 } 01440 01441 01442 void ContentType::setPartialParams(int total, int number) 01443 { 01444 TQCString num; 01445 num.setNum(number); 01446 setParameter("number", num); 01447 num.setNum(total); 01448 setParameter("total", num); 01449 } 01450 01451 01452 TQCString ContentType::getParameter(const char *name) 01453 { 01454 TQCString ret; 01455 int pos1=0, pos2=0; 01456 pos1=p_arams.find(name, 0, false); 01457 if(pos1!=-1) { 01458 if( (pos2=p_arams.find(';', pos1))==-1 ) 01459 pos2=p_arams.length(); 01460 pos1+=strlen(name)+1; 01461 ret=p_arams.mid(pos1, pos2-pos1); 01462 removeQuots(ret); 01463 } 01464 return ret; 01465 } 01466 01467 01468 void ContentType::setParameter(const TQCString &name, const TQCString &value, bool doubleQuotes) 01469 { 01470 int pos1=0, pos2=0; 01471 TQCString param; 01472 01473 if(doubleQuotes) 01474 param=name+"=\""+value+"\""; 01475 else 01476 param=name+"="+value; 01477 01478 pos1=p_arams.find(name.data(), 0, false); 01479 if(pos1==-1) { 01480 p_arams+="; "+param; 01481 } 01482 else { 01483 pos2=p_arams.find(';', pos1); 01484 if(pos2==-1) 01485 pos2=p_arams.length(); 01486 p_arams.remove(pos1, pos2-pos1); 01487 p_arams.insert(pos1, param.data()); 01488 } 01489 } 01490 01491 //-----</Content-Type>------------------------- 01492 01493 01494 01495 //-----<CTEncoding>---------------------------- 01496 01497 typedef struct { const char *s; int e; } encTableType; 01498 01499 static const encTableType encTable[] = { { "7Bit", CE7Bit }, 01500 { "8Bit", CE8Bit }, 01501 { "quoted-printable", CEquPr }, 01502 { "base64", CEbase64 }, 01503 { "x-uuencode", CEuuenc }, 01504 { "binary", CEbinary }, 01505 { 0, 0} }; 01506 01507 01508 void CTEncoding::from7BitString(const TQCString &s) 01509 { 01510 TQCString stripped(s.simplifyWhiteSpace()); 01511 c_te=CE7Bit; 01512 for(int i=0; encTable[i].s!=0; i++) 01513 if(strcasecmp(stripped.data(), encTable[i].s)==0) { 01514 c_te=(contentEncoding)encTable[i].e; 01515 break; 01516 } 01517 d_ecoded=( c_te==CE7Bit || c_te==CE8Bit ); 01518 01519 e_ncCS=cachedCharset(Latin1); 01520 } 01521 01522 01523 TQCString CTEncoding::as7BitString(bool incType) 01524 { 01525 TQCString str; 01526 for(int i=0; encTable[i].s!=0; i++) 01527 if(c_te==encTable[i].e) { 01528 str=encTable[i].s; 01529 break; 01530 } 01531 01532 if(incType) 01533 return ( typeIntro()+str ); 01534 else 01535 return str; 01536 } 01537 01538 01539 void CTEncoding::fromUnicodeString(const TQString &s, const TQCString&) 01540 { 01541 from7BitString( TQCString(s.latin1()) ); 01542 } 01543 01544 01545 TQString CTEncoding::asUnicodeString() 01546 { 01547 return TQString::fromLatin1(as7BitString(false)); 01548 } 01549 01550 //-----</CTEncoding>--------------------------- 01551 01552 01553 01554 //-----<CDisposition>-------------------------- 01555 01556 void CDisposition::from7BitString(const TQCString &s) 01557 { 01558 if(strncasecmp(s.data(), "attachment", 10)==0) 01559 d_isp=CDattachment; 01560 else d_isp=CDinline; 01561 01562 int pos=s.find("filename=", 0, false); 01563 TQCString fn; 01564 if(pos>-1) { 01565 pos+=9; 01566 fn=s.mid(pos, s.length()-pos); 01567 removeQuots(fn); 01568 f_ilename=decodeRFC2047String(fn, &e_ncCS, defaultCS(), forceCS()); 01569 } 01570 } 01571 01572 01573 TQCString CDisposition::as7BitString(bool incType) 01574 { 01575 TQCString ret; 01576 if(d_isp==CDattachment) 01577 ret="attachment"; 01578 else 01579 ret="inline"; 01580 01581 if(!f_ilename.isEmpty()) { 01582 if (isUsAscii(f_ilename)) { 01583 TQCString tmp(f_ilename.latin1()); 01584 addQuotes(tmp, true); 01585 ret+="; filename="+tmp; 01586 } else { 01587 // FIXME: encoded words can't be enclosed in quotes!! 01588 ret+="; filename=\""+encodeRFC2047String(f_ilename, e_ncCS)+"\""; 01589 } 01590 } 01591 01592 if(incType) 01593 return ( typeIntro()+ret ); 01594 else 01595 return ret; 01596 } 01597 01598 01599 void CDisposition::fromUnicodeString(const TQString &s, const TQCString &cs) 01600 { 01601 if(strncasecmp(s.latin1(), "attachment", 10)==0) 01602 d_isp=CDattachment; 01603 else d_isp=CDinline; 01604 01605 int pos=s.find("filename=", 0, false); 01606 if(pos>-1) { 01607 pos+=9; 01608 f_ilename=s.mid(pos, s.length()-pos); 01609 removeQuots(f_ilename); 01610 } 01611 01612 e_ncCS=cachedCharset(cs); 01613 } 01614 01615 01616 TQString CDisposition::asUnicodeString() 01617 { 01618 TQString ret; 01619 if(d_isp==CDattachment) 01620 ret="attachment"; 01621 else 01622 ret="inline"; 01623 01624 if(!f_ilename.isEmpty()) 01625 ret+="; filename=\""+f_ilename+"\""; 01626 01627 return ret; 01628 } 01629 01630 //-----</CDisposition>------------------------- 01631 #endif 01632 } // namespace Headers 01633 01634 } // namespace KMime