libkmime

kmime_headers.cpp
1/*
2 kmime_headers.cpp
3
4 KMime, the KDE internet mail/usenet news message library.
5 Copyright (c) 2001-2002 the KMime authors.
6 See file AUTHORS for details
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software Foundation,
14 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
15*/
16
17
18#include "kmime_headers.h"
19
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"
25
26#include "kqcstringsplitter.h"
27
28#include <tqtextcodec.h>
29#include <tqstring.h>
30#include <tqcstring.h>
31#include <tqstringlist.h>
32#include <tqvaluelist.h>
33
34#include <tdeglobal.h>
35#include <kcharsets.h>
36#include <krfcdate.h>
37
38#include <assert.h>
39
40
41using namespace KMime;
42using namespace KMime::Headers;
43using namespace KMime::Types;
44using namespace KMime::HeaderParsing;
45
46namespace KMime {
47namespace Headers {
48//-----<Base>----------------------------------
49
51{
52 if( (e_ncCS==0) || forceCS() )
53 return defaultCS();
54 else
55 return TQCString(e_ncCS);
56}
57
58
59void Base::setRFC2047Charset(const TQCString &cs)
60{
61 e_ncCS=cachedCharset(cs);
62}
63
64
66{
67 return ( p_arent!=0 ? p_arent->forceDefaultCS() : false );
68}
69
70
71TQCString Base::defaultCS()
72{
73 return ( p_arent!=0 ? p_arent->defaultCharset() : Latin1 );
74}
75
76
77//-----</Base>---------------------------------
78
79namespace Generics {
80
81//-----<GUnstructured>-------------------------
82
83void GUnstructured::from7BitString( const TQCString & str )
84{
85 d_ecoded = decodeRFC2047String( str, &e_ncCS, defaultCS(), forceCS() );
86}
87
88TQCString GUnstructured::as7BitString( bool withHeaderType )
89{
90 TQCString result;
91 if ( withHeaderType )
92 result = typeIntro();
93 result += encodeRFC2047String( d_ecoded, e_ncCS ) ;
94
95 return result;
96}
97
98void GUnstructured::fromUnicodeString( const TQString & str,
99 const TQCString & suggestedCharset )
100{
101 d_ecoded = str;
102 e_ncCS = cachedCharset( suggestedCharset );
103}
104
106{
107 return d_ecoded;
108}
109
110//-----</GUnstructured>-------------------------
111
112
113
114//-----<GStructured>-------------------------
115
116//-----</GStructured>-------------------------
117
118
119
120
121//-----<GAddress>-------------------------
122
123
124//-----</GAddress>-------------------------
125
126
127
128//-----<MailboxList>-------------------------
129
130bool MailboxList::parse( const char* & scursor, const char * const send,
131 bool isCRLF ) {
132 // examples:
133 // from := "From:" mailbox-list CRLF
134 // sender := "Sender:" mailbox CRLF
135
136 // parse an address-list:
137 TQValueList<Address> maybeAddressList;
138 if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) )
139 return false;
140
141 mMailboxList.clear();
142
143 // extract the mailboxes and complain if there are groups:
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;
149 }
150 mMailboxList += (*it).mailboxList;
151 }
152 return true;
153}
154
155//-----</MailboxList>-------------------------
156
157
158
159//-----<SingleMailbox>-------------------------
160
161bool SingleMailbox::parse( const char* & scursor, const char * const send,
162 bool isCRLF ) {
163 if ( !MailboxList::parse( scursor, send, isCRLF ) ) return false;
164
165 if ( mMailboxList.count() > 1 ) {
166 KMIME_WARN << "multiple mailboxes in header allowing only a single one!"
167 << endl;
168 }
169 return true;
170}
171
172//-----</SingleMailbox>-------------------------
173
174
175
176//-----<AddressList>-------------------------
177
178bool AddressList::parse( const char* & scursor, const char * const send,
179 bool isCRLF ) {
180
181 TQValueList<Address> maybeAddressList;
182 if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) )
183 return false;
184
185 mAddressList = maybeAddressList;
186 return true;
187}
188
189//-----</AddressList>-------------------------
190
191
192
193//-----<GToken>-------------------------
194
195bool GToken::parse( const char* & scursor, const char * const send,
196 bool isCRLF ) {
197
198 eatCFWS( scursor, send, isCRLF );
199 // must not be empty:
200 if ( scursor == send ) return false;
201
202 TQPair<const char*,int> maybeToken;
203 if ( !parseToken( scursor, send, maybeToken, false /* no 8bit chars */ ) )
204 return false;
205 mToken = TQCString( maybeToken.first, maybeToken.second );
206
207 // complain if trailing garbage is found:
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;
212 }
213 return true;
214}
215
216//-----</GToken>-------------------------
217
218
219
220//-----<GPhraseList>-------------------------
221
222bool GPhraseList::parse( const char* & scursor, const char * const send,
223 bool isCRLF ) {
224
225 mPhraseList.clear();
226
227 while ( scursor != send ) {
228 eatCFWS( scursor, send, isCRLF );
229 // empty entry ending the list: OK.
230 if ( scursor == send ) return true;
231 // empty entry: ignore.
232 if ( *scursor != ',' ) { scursor++; continue; }
233
234 TQString maybePhrase;
235 if ( !parsePhrase( scursor, send, maybePhrase, isCRLF ) )
236 return false;
237 mPhraseList.append( maybePhrase );
238
239 eatCFWS( scursor, send, isCRLF );
240 // non-empty entry ending the list: OK.
241 if ( scursor == send ) return true;
242 // comma separating the phrases: eat.
243 if ( *scursor != ',' ) scursor++;
244 }
245 return true;
246}
247
248//-----</GPhraseList>-------------------------
249
250
251
252//-----<GDotAtom>-------------------------
253
254bool GDotAtom::parse( const char* & scursor, const char * const send,
255 bool isCRLF ) {
256
257 TQString maybeDotAtom;
258 if ( !parseDotAtom( scursor, send, maybeDotAtom, isCRLF ) )
259 return false;
260
261 mDotAtom = maybeDotAtom;
262
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;
267 }
268 return true;
269}
270
271//-----</GDotAtom>-------------------------
272
273
274
275//-----<GParametrized>-------------------------
276
277//-----</GParametrized>-------------------------
278
279
280
281
282//-----</GContentType>-------------------------
283
284bool GContentType::parse( const char* & scursor, const char * const send,
285 bool isCRLF ) {
286
287 // content-type: type "/" subtype *(";" parameter)
288
289 mMimeType = 0;
290 mMimeSubType = 0;
291 mParameterHash.clear();
292
293 eatCFWS( scursor, send, isCRLF );
294 if ( scursor == send ) {
295 // empty header
296 return false;
297 }
298
299 //
300 // type
301 //
302
303 TQPair<const char*,int> maybeMimeType;
304 if ( !parseToken( scursor, send, maybeMimeType, false /* no 8Bit */ ) )
305 return false;
306
307 mMimeType = TQCString( maybeMimeType.first, maybeMimeType.second ).lower();
308
309 //
310 // subtype
311 //
312
313 eatCFWS( scursor, send, isCRLF );
314 if ( scursor == send || *scursor != '/' ) return false;
315 scursor++;
316 eatCFWS( scursor, send, isCRLF );
317 if ( scursor == send ) return false;
318
319 TQPair<const char*,int> maybeSubType;
320 if ( !parseToken( scursor, send, maybeSubType, false /* no 8bit */ ) )
321 return false;
322
323 mMimeSubType = TQCString( maybeSubType.first, maybeSubType.second ).lower();
324
325 //
326 // parameter list
327 //
328
329 eatCFWS( scursor, send, isCRLF );
330 if ( scursor == send ) return true; // no parameters
331
332 if ( *scursor != ';' ) return false;
333 scursor++;
334
335 if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) )
336 return false;
337
338 return true;
339}
340
341//-----</GContentType>-------------------------
342
343
344
345//-----<GTokenWithParameterList>-------------------------
346
347bool GCISTokenWithParameterList::parse( const char* & scursor,
348 const char * const send, bool isCRLF ) {
349
350 mToken = 0;
351 mParameterHash.clear();
352
353 //
354 // token
355 //
356
357 eatCFWS( scursor, send, isCRLF );
358 if ( scursor == send ) return false;
359
360 TQPair<const char*,int> maybeToken;
361 if ( !parseToken( scursor, send, maybeToken, false /* no 8Bit */ ) )
362 return false;
363
364 mToken = TQCString( maybeToken.first, maybeToken.second ).lower();
365
366 //
367 // parameter list
368 //
369
370 eatCFWS( scursor, send, isCRLF );
371 if ( scursor == send ) return true; // no parameters
372
373 if ( *scursor != ';' ) return false;
374 scursor++;
375
376 if ( !parseParameterList( scursor, send, mParameterHash, isCRLF ) )
377 return false;
378
379 return true;
380}
381
382//-----</GTokenWithParameterList>-------------------------
383
384
385
386//-----<GIdent>-------------------------
387
388bool GIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) {
389
390 // msg-id := "<" id-left "@" id-right ">"
391 // id-left := dot-atom-text / no-fold-quote / local-part
392 // id-right := dot-atom-text / no-fold-literal / domain
393 //
394 // equivalent to:
395 // msg-id := angle-addr
396
397 mMsgIdList.clear();
398
399 while ( scursor != send ) {
400 eatCFWS( scursor, send, isCRLF );
401 // empty entry ending the list: OK.
402 if ( scursor == send ) return true;
403 // empty entry: ignore.
404 if ( *scursor == ',' ) { scursor++; continue; }
405
406 AddrSpec maybeMsgId;
407 if ( !parseAngleAddr( scursor, send, maybeMsgId, isCRLF ) )
408 return false;
409 mMsgIdList.append( maybeMsgId );
410
411 eatCFWS( scursor, send, isCRLF );
412 // header end ending the list: OK.
413 if ( scursor == send ) return true;
414 // regular item separator: eat it.
415 if ( *scursor == ',' ) scursor++;
416 }
417 return true;
418}
419
420//-----</GIdent>-------------------------
421
422
423
424//-----<GSingleIdent>-------------------------
425
426bool GSingleIdent::parse( const char* & scursor, const char * const send, bool isCRLF ) {
427
428 if ( !GIdent::parse( scursor, send, isCRLF ) ) return false;
429
430 if ( mMsgIdList.count() > 1 ) {
431 KMIME_WARN << "more than one msg-id in header "
432 "allowing only a single one!" << endl;
433 }
434 return true;
435}
436
437//-----</GSingleIdent>-------------------------
438
439
440
441
442} // namespace Generics
443
444
445//-----<ReturnPath>-------------------------
446
447bool ReturnPath::parse( const char* & scursor, const char * const send, bool isCRLF ) {
448
449 eatCFWS( scursor, send, isCRLF );
450 if ( scursor == send ) return false;
451
452 const char * oldscursor = scursor;
453
454 Mailbox maybeMailbox;
455 if ( !parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) {
456 // mailbox parsing failed, but check for empty brackets:
457 scursor = oldscursor;
458 if ( *scursor != '<' ) return false;
459 scursor++;
460 eatCFWS( scursor, send, isCRLF );
461 if ( scursor == send || *scursor != '>' ) return false;
462 scursor++;
463
464 // prepare a Null mailbox:
465 AddrSpec emptyAddrSpec;
466 maybeMailbox.displayName = TQString();
467 maybeMailbox.addrSpec = emptyAddrSpec;
468 } else
469 // check that there was no display-name:
470 if ( !maybeMailbox.displayName.isEmpty() ) {
471 KMIME_WARN << "display-name \"" << maybeMailbox.displayName
472 << "\" in Return-Path!" << endl;
473 }
474
475 // see if that was all:
476 eatCFWS( scursor, send, isCRLF );
477 // and warn if it wasn't:
478 if ( scursor != send ) {
479 KMIME_WARN << "trailing garbage after angle-addr in Return-Path!" << endl;
480 }
481 return true;
482}
483
484//-----</ReturnPath>-------------------------
485
486
487
488
489//-----<Generic>-------------------------------
490
491void Generic::setType(const char *type)
492{
493 if(t_ype)
494 delete[] t_ype;
495 if(type) {
496 t_ype=new char[strlen(type)+1];
497 strcpy(t_ype, type);
498 }
499 else
500 t_ype=0;
501}
502
503//-----<Generic>-------------------------------
504
505
506#if !defined(KMIME_NEW_STYLE_CLASSTREE)
507//-----<MessageID>-----------------------------
508
509void MessageID::from7BitString(const TQCString &s)
510{
511 m_id=s;
512}
513
514
515TQCString MessageID::as7BitString(bool incType)
516{
517 if(incType)
518 return ( typeIntro()+m_id );
519 else
520 return m_id;
521}
522
523
524void MessageID::fromUnicodeString(const TQString &s, const TQCString&)
525{
526 m_id=s.latin1(); //Message-Ids can only contain us-ascii chars
527}
528
529
530TQString MessageID::asUnicodeString()
531{
532 return TQString::fromLatin1(m_id);
533}
534
535
536void MessageID::generate(const TQCString &fqdn)
537{
538 m_id="<"+uniqueString()+"@"+fqdn+">";
539}
540
541//-----</MessageID>----------------------------
542#endif
543
544
545//-----<Control>-------------------------------
546
547void Control::from7BitString(const TQCString &s)
548{
549 c_trlMsg=s;
550}
551
552
553TQCString Control::as7BitString(bool incType)
554{
555 if(incType)
556 return ( typeIntro()+c_trlMsg );
557 else
558 return c_trlMsg;
559}
560
561
562void Control::fromUnicodeString(const TQString &s, const TQCString&)
563{
564 c_trlMsg=s.latin1();
565}
566
567
569{
570 return TQString::fromLatin1(c_trlMsg);
571}
572
573//-----</Control>------------------------------
574
575
576
577#if !defined(KMIME_NEW_STYLE_CLASSTREE)
578//-----<AddressField>--------------------------
579void AddressField::from7BitString(const TQCString &s)
580{
581 int pos1=0, pos2=0, type=0;
582 TQCString n;
583
584 //so what do we have here ?
585 if(s.find( TQRegExp("*@*(*)", false, true) )!=-1) type=2; // From: foo@bar.com (John Doe)
586 else if(s.find( TQRegExp("*<*@*>", false, true) )!=-1) type=1; // From: John Doe <foo@bar.com>
587 else if(s.find( TQRegExp("*@*", false, true) )!=-1) type=0; // From: foo@bar.com
588 else { //broken From header => just decode it
589 n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS());
590 return;
591 }
592
593 switch(type) {
594
595 case 0:
596 e_mail=s.copy();
597 break;
598
599 case 1:
600 pos1=0;
601 pos2=s.find('<');
602 if(pos2!=-1) {
603 n=s.mid(pos1, pos2-pos1).stripWhiteSpace();
604 pos1=pos2+1;
605 pos2=s.find('>', pos1);
606 if(pos2!=-1)
607 e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace();
608 }
609 else return;
610 break;
611
612 case 2:
613 pos1=0;
614 pos2=s.find('(');
615 if(pos2!=-1) {
616 e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace();
617 pos1=pos2+1;
618 pos2=s.find(')', pos1);
619 if(pos2!=-1)
620 n=s.mid(pos1, pos2-pos1).stripWhiteSpace();
621 }
622 break;
623
624 default: break;
625 }
626
627 if(!n.isEmpty()) {
628 removeQuots(n);
629 n_ame=decodeRFC2047String(n, &e_ncCS, defaultCS(), forceCS());
630 }
631}
632
633
634TQCString AddressField::as7BitString(bool incType)
635{
636 TQCString ret;
637
638 if(incType && type()[0]!='\0')
639 ret=typeIntro();
640
641 if(n_ame.isEmpty())
642 ret+=e_mail;
643 else {
644 if (isUsAscii(n_ame)) {
645 TQCString tmp(n_ame.latin1());
646 addQuotes(tmp, false);
647 ret+=tmp;
648 } else {
649 ret+=encodeRFC2047String(n_ame, e_ncCS, true);
650 }
651 if (!e_mail.isEmpty())
652 ret += " <"+e_mail+">";
653 }
654
655 return ret;
656}
657
658
659void AddressField::fromUnicodeString(const TQString &s, const TQCString &cs)
660{
661 int pos1=0, pos2=0, type=0;
662 TQCString n;
663
664 e_ncCS=cachedCharset(cs);
665
666 //so what do we have here ?
667 if(s.find( TQRegExp("*@*(*)", false, true) )!=-1) type=2; // From: foo@bar.com (John Doe)
668 else if(s.find( TQRegExp("*<*@*>", false, true) )!=-1) type=1; // From: John Doe <foo@bar.com>
669 else if(s.find( TQRegExp("*@*", false, true) )!=-1) type=0; // From: foo@bar.com
670 else { //broken From header => just copy it
671 n_ame=s;
672 return;
673 }
674
675 switch(type) {
676
677 case 0:
678 e_mail=s.latin1();
679 break;
680
681 case 1:
682 pos1=0;
683 pos2=s.find('<');
684 if(pos2!=-1) {
685 n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace();
686 pos1=pos2+1;
687 pos2=s.find('>', pos1);
688 if(pos2!=-1)
689 e_mail=s.mid(pos1, pos2-pos1).latin1();
690 }
691 else return;
692 break;
693
694 case 2:
695 pos1=0;
696 pos2=s.find('(');
697 if(pos2!=-1) {
698 e_mail=s.mid(pos1, pos2-pos1).stripWhiteSpace().latin1();
699 pos1=pos2+1;
700 pos2=s.find(')', pos1);
701 if(pos2!=-1)
702 n_ame=s.mid(pos1, pos2-pos1).stripWhiteSpace();
703 }
704 break;
705
706 default: break;
707 }
708
709 if(!n_ame.isEmpty())
710 removeQuots(n_ame);
711}
712
713
714TQString AddressField::asUnicodeString()
715{
716 if(n_ame.isEmpty())
717 return TQString(e_mail);
718 else {
719 TQString s = n_ame;
720 if (!e_mail.isEmpty())
721 s += " <"+e_mail+">";
722 return s;
723 }
724}
725
726
727TQCString AddressField::nameAs7Bit()
728{
729 return encodeRFC2047String(n_ame, e_ncCS);
730}
731
732
733void AddressField::setNameFrom7Bit(const TQCString &s)
734{
735 n_ame=decodeRFC2047String(s, &e_ncCS, defaultCS(), forceCS());
736}
737
738//-----</AddressField>-------------------------
739#endif
740
741
742//-----<MailCopiesTo>--------------------------
743
744bool MailCopiesTo::isValid()
745{
746 if (hasEmail())
747 return true;
748
749 if ((n_ame == "nobody") ||
750 (n_ame == "never") ||
751 (n_ame == "poster") ||
752 (n_ame == "always"))
753 return true;
754 else
755 return false;
756}
757
758
759bool MailCopiesTo::alwaysCopy()
760{
761 return (hasEmail() || (n_ame == "poster") || (n_ame == "always"));
762}
763
764
765bool MailCopiesTo::neverCopy()
766{
767 return ((n_ame == "nobody") || (n_ame == "never"));
768}
769
770//-----</MailCopiesTo>-------------------------
771
772
773
774
775//-----<Date>----------------------------------
776
777void Date::from7BitString(const TQCString &s)
778{
779 t_ime=KRFCDate::parseDate(s);
780}
781
782
783TQCString Date::as7BitString(bool incType)
784{
785 if(incType)
786 return ( typeIntro()+KRFCDate::rfc2822DateString(t_ime) );
787 else
788 return TQCString(KRFCDate::rfc2822DateString(t_ime));
789}
790
791
792void Date::fromUnicodeString(const TQString &s, const TQCString&)
793{
794 from7BitString( TQCString(s.latin1()) );
795}
796
797
799{
800 return TQString::fromLatin1(as7BitString(false));
801}
802
803
804TQDateTime Date::qdt()
805{
806 TQDateTime dt;
807 dt.setTime_t(t_ime);
808 return dt;
809}
810
811
812int Date::ageInDays()
813{
814 TQDate today=TQDate::currentDate();
815 return ( qdt().date().daysTo(today) );
816}
817
818//-----</Date>---------------------------------
819
820
821
822#if !defined(KMIME_NEW_STYLE_CLASSTREE)
823//-----<To>------------------------------------
824
825void To::from7BitString(const TQCString &s)
826{
827 if(a_ddrList)
828 a_ddrList->clear();
829 else {
830 a_ddrList=new TQPtrList<AddressField>;
831 a_ddrList->setAutoDelete(true);
832 }
833
834 KTQCStringSplitter split;
835 split.init(s, ",");
836 bool splitOk=split.first();
837 if(!splitOk)
838 a_ddrList->append( new AddressField(p_arent, s ));
839 else {
840 do {
841 a_ddrList->append( new AddressField(p_arent, split.string()) );
842 } while(split.next());
843 }
844
845 e_ncCS=cachedCharset(a_ddrList->first()->rfc2047Charset());
846}
847
848
849TQCString To::as7BitString(bool incType)
850{
851 TQCString ret;
852
853 if(incType)
854 ret+=typeIntro();
855
856 if (a_ddrList) {
857 AddressField *it=a_ddrList->first();
858 if (it)
859 ret+=it->as7BitString(false);
860 for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() )
861 ret+=","+it->as7BitString(false);
862 }
863
864 return ret;
865}
866
867
868void To::fromUnicodeString(const TQString &s, const TQCString &cs)
869{
870 if(a_ddrList)
871 a_ddrList->clear();
872 else {
873 a_ddrList=new TQPtrList<AddressField>;
874 a_ddrList->setAutoDelete(true);
875 }
876
877 TQStringList l=TQStringList::split(",", s);
878
879 TQStringList::Iterator it=l.begin();
880 for(; it!=l.end(); ++it)
881 a_ddrList->append(new AddressField( p_arent, (*it), cs ));
882
883 e_ncCS=cachedCharset(cs);
884}
885
886
887TQString To::asUnicodeString()
888{
889 if(!a_ddrList)
890 return TQString();
891
892 TQString ret;
893 AddressField *it=a_ddrList->first();
894
895 if (it)
896 ret+=it->asUnicodeString();
897 for (it=a_ddrList->next() ; it != 0; it=a_ddrList->next() )
898 ret+=","+it->asUnicodeString();
899 return ret;
900}
901
902
903void To::addAddress(const AddressField &a)
904{
905 if(!a_ddrList) {
906 a_ddrList=new TQPtrList<AddressField>;
907 a_ddrList->setAutoDelete(true);
908 }
909
910 AddressField *add=new AddressField(a);
911 add->setParent(p_arent);
912 a_ddrList->append(add);
913}
914
915
916void To::emails(TQStrList *l)
917{
918 l->clear();
919
920 for (AddressField *it=a_ddrList->first(); it != 0; it=a_ddrList->next() )
921 if( it->hasEmail() )
922 l->append( it->email() );
923}
924
925void To::names(TQStringList *l)
926{
927 l->clear();
928
929 for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() )
930 if( it->hasName() )
931 l->append( it->name() );
932}
933
934void To::displayNames(TQStringList *l)
935{
936 l->clear();
937
938 for (AddressField *it=a_ddrList->first(); it != 0 ; it=a_ddrList->next() )
939 l->append( it->asUnicodeString() );
940}
941
942//-----</To>-----------------------------------
943#endif
944
945
946//-----<Newsgroups>----------------------------
947
948void Newsgroups::from7BitString(const TQCString &s)
949{
950 g_roups=s;
951 e_ncCS=cachedCharset("UTF-8");
952}
953
954
955TQCString Newsgroups::as7BitString(bool incType)
956{
957 if(incType)
958 return (typeIntro()+g_roups);
959 else
960 return g_roups;
961}
962
963
964void Newsgroups::fromUnicodeString(const TQString &s, const TQCString&)
965{
966 g_roups=s.utf8();
967 e_ncCS=cachedCharset("UTF-8");
968}
969
970
972{
973 return TQString::fromUtf8(g_roups);
974}
975
976
977TQCString Newsgroups::firstGroup()
978{
979 int pos=0;
980 if(!g_roups.isEmpty()) {
981 pos=g_roups.find(',');
982 if(pos==-1)
983 return g_roups;
984 else
985 return g_roups.left(pos);
986 }
987 else
988 return TQCString();
989}
990
991
992TQStringList Newsgroups::getGroups()
993{
994 TQStringList temp = TQStringList::split(',', g_roups);
995 TQStringList ret;
996 TQString s;
997
998 for (TQStringList::Iterator it = temp.begin(); it != temp.end(); ++it ) {
999 s = (*it).simplifyWhiteSpace();
1000 ret.append(s);
1001 }
1002
1003 return ret;
1004}
1005
1006//-----</Newsgroups>---------------------------
1007
1008
1009
1010//-----<Lines>---------------------------------
1011
1012void Lines::from7BitString(const TQCString &s)
1013{
1014 l_ines=s.toInt();
1015 e_ncCS=cachedCharset(Latin1);
1016}
1017
1018
1019TQCString Lines::as7BitString(bool incType)
1020{
1021 TQCString num;
1022 num.setNum(l_ines);
1023
1024 if(incType)
1025 return ( typeIntro()+num );
1026 else
1027 return num;
1028}
1029
1030
1031void Lines::fromUnicodeString(const TQString &s, const TQCString&)
1032{
1033 l_ines=s.toInt();
1034 e_ncCS=cachedCharset(Latin1);
1035}
1036
1037
1039{
1040 TQString num;
1041 num.setNum(l_ines);
1042
1043 return num;
1044}
1045
1046//-----</Lines>--------------------------------
1047
1048
1049
1050#if !defined(KMIME_NEW_STYLE_CLASSTREE)
1051//-----<References>----------------------------
1052
1053void References::from7BitString(const TQCString &s)
1054{
1055 r_ef=s;
1056 e_ncCS=cachedCharset(Latin1);
1057}
1058
1059
1060TQCString References::as7BitString(bool incType)
1061{
1062 if(incType)
1063 return ( typeIntro()+r_ef );
1064 else
1065 return r_ef;
1066}
1067
1068
1069void References::fromUnicodeString(const TQString &s, const TQCString&)
1070{
1071 r_ef=s.latin1();
1072 e_ncCS=cachedCharset(Latin1);
1073}
1074
1075
1076TQString References::asUnicodeString()
1077{
1078 return TQString::fromLatin1(r_ef);
1079}
1080
1081
1082int References::count()
1083{
1084 int cnt1=0, cnt2=0;
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++;
1090 }
1091
1092 if(cnt1<cnt2) return cnt1;
1093 else return cnt2;
1094}
1095
1096
1097TQCString References::first()
1098{
1099 p_os=-1;
1100 return next();
1101}
1102
1103
1104TQCString References::next()
1105{
1106 int pos1=0, pos2=0;
1107 TQCString ret;
1108
1109 if(p_os!=0) {
1110 pos2=r_ef.findRev('>', p_os);
1111 p_os=0;
1112 if(pos2!=-1) {
1113 pos1=r_ef.findRev('<', pos2);
1114 if(pos1!=-1) {
1115 ret=r_ef.mid(pos1, pos2-pos1+1);
1116 p_os=pos1;
1117 }
1118 }
1119 }
1120 return ret;
1121}
1122
1123
1124TQCString References::at(unsigned int i)
1125{
1126 TQCString ret;
1127 int pos1=0, pos2=0;
1128 unsigned int cnt=0;
1129
1130 while(pos1!=-1 && cnt < i+1) {
1131 pos2=pos1-1;
1132 pos1=r_ef.findRev('<', pos2);
1133 cnt++;
1134 }
1135
1136 if(pos1!=-1) {
1137 pos2=r_ef.find('>', pos1);
1138 if(pos2!=-1)
1139 ret=r_ef.mid(pos1, pos2-pos1+1);
1140 }
1141
1142 return ret;
1143}
1144
1145
1146void References::append(const TQCString &s)
1147{
1148 TQString temp=r_ef.data();
1149 temp += " ";
1150 temp += s.data();
1151 TQStringList lst=TQStringList::split(' ',temp);
1152 TQRegExp exp("^<.+@.+>$");
1153
1154 // remove bogus references
1155 TQStringList::Iterator it = lst.begin();
1156 while (it != lst.end()) {
1157 if (-1==(*it).find(exp))
1158 it = lst.remove(it);
1159 else
1160 it++;
1161 }
1162
1163 if (lst.isEmpty()) {
1164 r_ef = s.copy(); // shouldn't happen...
1165 return;
1166 } else
1167 r_ef = "";
1168
1169 temp = lst.first(); // include the first id
1170 r_ef = temp.latin1();
1171 lst.remove(temp); // avoids duplicates
1172 int insPos = r_ef.length();
1173
1174 for (int i=1;i<=3;i++) { // include the last three ids
1175 if (!lst.isEmpty()) {
1176 temp = lst.last();
1177 r_ef.insert(insPos,(TQString(" %1").arg(temp)).latin1());
1178 lst.remove(temp);
1179 } else
1180 break;
1181 }
1182
1183 while (!lst.isEmpty()) { // now insert the rest, up to 1000 characters
1184 temp = lst.last();
1185 if ((15+r_ef.length()+temp.length())<1000) {
1186 r_ef.insert(insPos,(TQString(" %1").arg(temp)).latin1());
1187 lst.remove(temp);
1188 } else
1189 return;
1190 }
1191}
1192
1193//-----</References>---------------------------
1194#endif
1195
1196
1197//-----<UserAgent>-----------------------------
1198
1199void UserAgent::from7BitString(const TQCString &s)
1200{
1201 u_agent=s;
1202 e_ncCS=cachedCharset(Latin1);
1203}
1204
1205
1206TQCString UserAgent::as7BitString(bool incType)
1207{
1208 if(incType)
1209 return ( typeIntro()+u_agent );
1210 else
1211 return u_agent;
1212}
1213
1214
1215void UserAgent::fromUnicodeString(const TQString &s, const TQCString&)
1216{
1217 u_agent=s.latin1();
1218 e_ncCS=cachedCharset(Latin1);
1219}
1220
1221
1223{
1224 return TQString::fromLatin1(u_agent);
1225}
1226
1227//-----</UserAgent>----------------------------
1228
1229
1230
1231#if !defined(KMIME_NEW_STYLE_CLASSTREE)
1232//-----<Content-Type>--------------------------
1233
1234void ContentType::from7BitString(const TQCString &s)
1235{
1236 int pos=s.find(';');
1237
1238 if(pos==-1)
1239 m_imeType=s.simplifyWhiteSpace();
1240 else {
1241 m_imeType=s.left(pos).simplifyWhiteSpace();
1242 p_arams=s.mid(pos, s.length()-pos).simplifyWhiteSpace();
1243 }
1244
1245 if(isMultipart())
1246 c_ategory=CCcontainer;
1247 else
1248 c_ategory=CCsingle;
1249
1250 e_ncCS=cachedCharset(Latin1);
1251}
1252
1253
1254TQCString ContentType::as7BitString(bool incType)
1255{
1256 if(incType)
1257 return (typeIntro()+m_imeType+p_arams);
1258 else
1259 return (m_imeType+p_arams);
1260}
1261
1262
1263void ContentType::fromUnicodeString(const TQString &s, const TQCString&)
1264{
1265 from7BitString( TQCString(s.latin1()) );
1266}
1267
1268
1269TQString ContentType::asUnicodeString()
1270{
1271 return TQString::fromLatin1(as7BitString(false));
1272}
1273
1274
1275TQCString ContentType::mediaType()
1276{
1277 int pos=m_imeType.find('/');
1278 if(pos==-1)
1279 return m_imeType;
1280 else
1281 return m_imeType.left(pos);
1282}
1283
1284
1285TQCString ContentType::subType()
1286{
1287 int pos=m_imeType.find('/');
1288 if(pos==-1)
1289 return TQCString();
1290 else
1291 return m_imeType.mid(pos, m_imeType.length()-pos);
1292}
1293
1294
1295void ContentType::setMimeType(const TQCString &s)
1296{
1297 p_arams.resize(0);
1298 m_imeType=s;
1299
1300 if(isMultipart())
1301 c_ategory=CCcontainer;
1302 else
1303 c_ategory=CCsingle;
1304}
1305
1306
1307bool ContentType::isMediatype(const char *s)
1308{
1309 return ( strncasecmp(m_imeType.data(), s, strlen(s)) );
1310}
1311
1312
1313bool ContentType::isSubtype(const char *s)
1314{
1315 char *c=strchr(m_imeType.data(), '/');
1316
1317 if( (c==0) || (*(c+1)=='\0') )
1318 return false;
1319 else
1320 return ( strcasecmp(c+1, s)==0 );
1321}
1322
1323
1324bool ContentType::isText()
1325{
1326 return (strncasecmp(m_imeType.data(), "text", 4)==0);
1327}
1328
1329
1330bool ContentType::isPlainText()
1331{
1332 return (strcasecmp(m_imeType.data(), "text/plain")==0);
1333}
1334
1335
1336bool ContentType::isHTMLText()
1337{
1338 return (strcasecmp(m_imeType.data(), "text/html")==0);
1339}
1340
1341
1342bool ContentType::isImage()
1343{
1344 return (strncasecmp(m_imeType.data(), "image", 5)==0);
1345}
1346
1347
1348bool ContentType::isMultipart()
1349{
1350 return (strncasecmp(m_imeType.data(), "multipart", 9)==0);
1351}
1352
1353
1354bool ContentType::isPartial()
1355{
1356 return (strcasecmp(m_imeType.data(), "message/partial")==0);
1357}
1358
1359
1360TQCString ContentType::charset()
1361{
1362 TQCString ret=getParameter("charset");
1363 if( ret.isEmpty() || forceCS() ) { //we return the default-charset if necessary
1364 ret=defaultCS();
1365 }
1366 return ret;
1367}
1368
1369
1370void ContentType::setCharset(const TQCString &s)
1371{
1372 setParameter("charset", s);
1373}
1374
1375
1376TQCString ContentType::boundary()
1377{
1378 return getParameter("boundary");
1379}
1380
1381
1382void ContentType::setBoundary(const TQCString &s)
1383{
1384 setParameter("boundary", s, true);
1385}
1386
1387
1388TQString ContentType::name()
1389{
1390 const char *dummy=0;
1391 return ( decodeRFC2047String(getParameter("name"), &dummy, defaultCS(), forceCS()) );
1392}
1393
1394
1395void ContentType::setName(const TQString &s, const TQCString &cs)
1396{
1397 e_ncCS=cs;
1398
1399 if (isUsAscii(s)) {
1400 TQCString tmp(s.latin1());
1401 addQuotes(tmp, true);
1402 setParameter("name", tmp, false);
1403 } else {
1404 // FIXME: encoded words can't be enclosed in quotes!!
1405 setParameter("name", encodeRFC2047String(s, cs), true);
1406 }
1407}
1408
1409
1410TQCString ContentType::id()
1411{
1412 return (getParameter("id"));
1413}
1414
1415
1416void ContentType::setId(const TQCString &s)
1417{
1418 setParameter("id", s, true);
1419}
1420
1421
1422int ContentType::partialNumber()
1423{
1424 TQCString p=getParameter("number");
1425 if(!p.isEmpty())
1426 return p.toInt();
1427 else
1428 return -1;
1429}
1430
1431
1432int ContentType::partialCount()
1433{
1434 TQCString p=getParameter("total");
1435 if(!p.isEmpty())
1436 return p.toInt();
1437 else
1438 return -1;
1439}
1440
1441
1442void ContentType::setPartialParams(int total, int number)
1443{
1444 TQCString num;
1445 num.setNum(number);
1446 setParameter("number", num);
1447 num.setNum(total);
1448 setParameter("total", num);
1449}
1450
1451
1452TQCString ContentType::getParameter(const char *name)
1453{
1454 TQCString ret;
1455 int pos1=0, pos2=0;
1456 pos1=p_arams.find(name, 0, false);
1457 if(pos1!=-1) {
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);
1462 removeQuots(ret);
1463 }
1464 return ret;
1465}
1466
1467
1468void ContentType::setParameter(const TQCString &name, const TQCString &value, bool doubleQuotes)
1469{
1470 int pos1=0, pos2=0;
1471 TQCString param;
1472
1473 if(doubleQuotes)
1474 param=name+"=\""+value+"\"";
1475 else
1476 param=name+"="+value;
1477
1478 pos1=p_arams.find(name.data(), 0, false);
1479 if(pos1==-1) {
1480 p_arams+="; "+param;
1481 }
1482 else {
1483 pos2=p_arams.find(';', pos1);
1484 if(pos2==-1)
1485 pos2=p_arams.length();
1486 p_arams.remove(pos1, pos2-pos1);
1487 p_arams.insert(pos1, param.data());
1488 }
1489}
1490
1491//-----</Content-Type>-------------------------
1492
1493
1494
1495//-----<CTEncoding>----------------------------
1496
1497typedef struct { const char *s; int e; } encTableType;
1498
1499static const encTableType encTable[] = { { "7Bit", CE7Bit },
1500 { "8Bit", CE8Bit },
1501 { "quoted-printable", CEquPr },
1502 { "base64", CEbase64 },
1503 { "x-uuencode", CEuuenc },
1504 { "binary", CEbinary },
1505 { 0, 0} };
1506
1507
1508void CTEncoding::from7BitString(const TQCString &s)
1509{
1510 TQCString stripped(s.simplifyWhiteSpace());
1511 c_te=CE7Bit;
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;
1515 break;
1516 }
1517 d_ecoded=( c_te==CE7Bit || c_te==CE8Bit );
1518
1519 e_ncCS=cachedCharset(Latin1);
1520}
1521
1522
1523TQCString CTEncoding::as7BitString(bool incType)
1524{
1525 TQCString str;
1526 for(int i=0; encTable[i].s!=0; i++)
1527 if(c_te==encTable[i].e) {
1528 str=encTable[i].s;
1529 break;
1530 }
1531
1532 if(incType)
1533 return ( typeIntro()+str );
1534 else
1535 return str;
1536}
1537
1538
1539void CTEncoding::fromUnicodeString(const TQString &s, const TQCString&)
1540{
1541 from7BitString( TQCString(s.latin1()) );
1542}
1543
1544
1545TQString CTEncoding::asUnicodeString()
1546{
1547 return TQString::fromLatin1(as7BitString(false));
1548}
1549
1550//-----</CTEncoding>---------------------------
1551
1552
1553
1554//-----<CDisposition>--------------------------
1555
1556void CDisposition::from7BitString(const TQCString &s)
1557{
1558 if(strncasecmp(s.data(), "attachment", 10)==0)
1559 d_isp=CDattachment;
1560 else d_isp=CDinline;
1561
1562 int pos=s.find("filename=", 0, false);
1563 TQCString fn;
1564 if(pos>-1) {
1565 pos+=9;
1566 fn=s.mid(pos, s.length()-pos);
1567 removeQuots(fn);
1568 f_ilename=decodeRFC2047String(fn, &e_ncCS, defaultCS(), forceCS());
1569 }
1570}
1571
1572
1573TQCString CDisposition::as7BitString(bool incType)
1574{
1575 TQCString ret;
1576 if(d_isp==CDattachment)
1577 ret="attachment";
1578 else
1579 ret="inline";
1580
1581 if(!f_ilename.isEmpty()) {
1582 if (isUsAscii(f_ilename)) {
1583 TQCString tmp(f_ilename.latin1());
1584 addQuotes(tmp, true);
1585 ret+="; filename="+tmp;
1586 } else {
1587 // FIXME: encoded words can't be enclosed in quotes!!
1588 ret+="; filename=\""+encodeRFC2047String(f_ilename, e_ncCS)+"\"";
1589 }
1590 }
1591
1592 if(incType)
1593 return ( typeIntro()+ret );
1594 else
1595 return ret;
1596}
1597
1598
1599void CDisposition::fromUnicodeString(const TQString &s, const TQCString &cs)
1600{
1601 if(strncasecmp(s.latin1(), "attachment", 10)==0)
1602 d_isp=CDattachment;
1603 else d_isp=CDinline;
1604
1605 int pos=s.find("filename=", 0, false);
1606 if(pos>-1) {
1607 pos+=9;
1608 f_ilename=s.mid(pos, s.length()-pos);
1609 removeQuots(f_ilename);
1610 }
1611
1612 e_ncCS=cachedCharset(cs);
1613}
1614
1615
1616TQString CDisposition::asUnicodeString()
1617{
1618 TQString ret;
1619 if(d_isp==CDattachment)
1620 ret="attachment";
1621 else
1622 ret="inline";
1623
1624 if(!f_ilename.isEmpty())
1625 ret+="; filename=\""+f_ilename+"\"";
1626
1627 return ret;
1628}
1629
1630//-----</CDisposition>-------------------------
1631#endif
1632} // namespace Headers
1633
1634} // namespace KMime
This class encapsulates an address-field, containing an email-address and a real name.
TQCString rfc2047Charset()
Return the charset that is used for RFC2047-encoding.
bool forceCS()
Return if the default charset is mandatory.
TQCString defaultCS()
Return the default charset.
void setRFC2047Charset(const TQCString &cs)
Set the charset for RFC2047-encoding.
virtual TQString asUnicodeString()
Return the decoded content of the header without the header-type.
virtual TQCString as7BitString(bool incType=true)
Return the encoded header.
virtual void fromUnicodeString(const TQString &s, const TQCString &)
Parse the given string and set the charset.
virtual void from7BitString(const TQCString &s)
Parse the given string.
virtual TQCString as7BitString(bool incType=true)
Return the encoded header.
virtual TQString asUnicodeString()
Return the decoded content of the header without the header-type.
virtual void from7BitString(const TQCString &s)
Parse the given string.
virtual void fromUnicodeString(const TQString &s, const TQCString &)
Parse the given string and set the charset.
virtual const char * type()
Return the type of this header (e.g.
TQValueList< Types::Address > mAddressList
The list of addresses.
TQValueList< Types::AddrSpec > mMsgIdList
The list of msg-id's.
virtual void fromUnicodeString(const TQString &str, const TQCString &suggestedCharset)
Parse the given string and set the charset.
virtual void from7BitString(const TQCString &str)
Parse the given string.
virtual TQCString as7BitString(bool withHeaderType=true)
Return the encoded header.
virtual TQString asUnicodeString()
Return the decoded content of the header without the header-type.
TQValueList< Types::Mailbox > mMailboxList
The list of mailboxes.
virtual TQCString as7BitString(bool incType=true)
Return the encoded header.
virtual void from7BitString(const TQCString &s)
Parse the given string.
virtual void fromUnicodeString(const TQString &s, const TQCString &)
Parse the given string and set the charset.
virtual TQString asUnicodeString()
Return the decoded content of the header without the header-type.
virtual TQString asUnicodeString()
Return the decoded content of the header without the header-type.
virtual void from7BitString(const TQCString &s)
Parse the given string.
virtual void fromUnicodeString(const TQString &s, const TQCString &)
Parse the given string and set the charset.
virtual TQCString as7BitString(bool incType=true)
Return the encoded header.
virtual TQString asUnicodeString()
Return the decoded content of the header without the header-type.
virtual void fromUnicodeString(const TQString &s, const TQCString &)
Parse the given string and set the charset.
virtual void from7BitString(const TQCString &s)
Parse the given string.
virtual TQCString as7BitString(bool incType=true)
Return the encoded header.