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 
41 using namespace KMime;
42 using namespace KMime::Headers;
43 using namespace KMime::Types;
44 using namespace KMime::HeaderParsing;
45 
46 namespace KMime {
47 namespace Headers {
48 //-----<Base>----------------------------------
49 
51 {
52  if( (e_ncCS==0) || forceCS() )
53  return defaultCS();
54  else
55  return TQCString(e_ncCS);
56 }
57 
58 
59 void 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 
71 TQCString Base::defaultCS()
72 {
73  return ( p_arent!=0 ? p_arent->defaultCharset() : Latin1 );
74 }
75 
76 
77 //-----</Base>---------------------------------
78 
79 namespace Generics {
80 
81 //-----<GUnstructured>-------------------------
82 
83 void GUnstructured::from7BitString( const TQCString & str )
84 {
85  d_ecoded = decodeRFC2047String( str, &e_ncCS, defaultCS(), forceCS() );
86 }
87 
88 TQCString 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 
98 void GUnstructured::fromUnicodeString( const TQString & str,
99  const TQCString & suggestedCharset )
100 {
101  d_ecoded = str;
102  e_ncCS = cachedCharset( suggestedCharset );
103 }
104 
105 TQString GUnstructured::asUnicodeString()
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 
130 bool 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 
161 bool 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 
178 bool 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 
195 bool 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 
222 bool 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 
254 bool 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 
284 bool 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 
347 bool 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 
388 bool 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 
426 bool 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 
447 bool 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 
491 void 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 
509 void MessageID::from7BitString(const TQCString &s)
510 {
511  m_id=s;
512 }
513 
514 
515 TQCString MessageID::as7BitString(bool incType)
516 {
517  if(incType)
518  return ( typeIntro()+m_id );
519  else
520  return m_id;
521 }
522 
523 
524 void MessageID::fromUnicodeString(const TQString &s, const TQCString&)
525 {
526  m_id=s.latin1(); //Message-Ids can only contain us-ascii chars
527 }
528 
529 
530 TQString MessageID::asUnicodeString()
531 {
532  return TQString::fromLatin1(m_id);
533 }
534 
535 
536 void MessageID::generate(const TQCString &fqdn)
537 {
538  m_id="<"+uniqueString()+"@"+fqdn+">";
539 }
540 
541 //-----</MessageID>----------------------------
542 #endif
543 
544 
545 //-----<Control>-------------------------------
546 
547 void Control::from7BitString(const TQCString &s)
548 {
549  c_trlMsg=s;
550 }
551 
552 
553 TQCString Control::as7BitString(bool incType)
554 {
555  if(incType)
556  return ( typeIntro()+c_trlMsg );
557  else
558  return c_trlMsg;
559 }
560 
561 
562 void 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>--------------------------
579 void 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 
634 TQCString 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 
659 void 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 
714 TQString 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 
727 TQCString AddressField::nameAs7Bit()
728 {
729  return encodeRFC2047String(n_ame, e_ncCS);
730 }
731 
732 
733 void 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 
744 bool 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 
759 bool MailCopiesTo::alwaysCopy()
760 {
761  return (hasEmail() || (n_ame == "poster") || (n_ame == "always"));
762 }
763 
764 
765 bool MailCopiesTo::neverCopy()
766 {
767  return ((n_ame == "nobody") || (n_ame == "never"));
768 }
769 
770 //-----</MailCopiesTo>-------------------------
771 
772 
773 
774 
775 //-----<Date>----------------------------------
776 
777 void Date::from7BitString(const TQCString &s)
778 {
779  t_ime=KRFCDate::parseDate(s);
780 }
781 
782 
783 TQCString 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 
792 void 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 
804 TQDateTime Date::qdt()
805 {
806  TQDateTime dt;
807  dt.setTime_t(t_ime);
808  return dt;
809 }
810 
811 
812 int 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 
825 void 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 
849 TQCString 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 
868 void 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 
887 TQString 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 
903 void 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 
916 void 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 
925 void 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 
934 void 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 
948 void Newsgroups::from7BitString(const TQCString &s)
949 {
950  g_roups=s;
951  e_ncCS=cachedCharset("UTF-8");
952 }
953 
954 
955 TQCString Newsgroups::as7BitString(bool incType)
956 {
957  if(incType)
958  return (typeIntro()+g_roups);
959  else
960  return g_roups;
961 }
962 
963 
964 void 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 
977 TQCString 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 
992 TQStringList 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 
1012 void Lines::from7BitString(const TQCString &s)
1013 {
1014  l_ines=s.toInt();
1015  e_ncCS=cachedCharset(Latin1);
1016 }
1017 
1018 
1019 TQCString 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 
1031 void 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 
1053 void References::from7BitString(const TQCString &s)
1054 {
1055  r_ef=s;
1056  e_ncCS=cachedCharset(Latin1);
1057 }
1058 
1059 
1060 TQCString References::as7BitString(bool incType)
1061 {
1062  if(incType)
1063  return ( typeIntro()+r_ef );
1064  else
1065  return r_ef;
1066 }
1067 
1068 
1069 void References::fromUnicodeString(const TQString &s, const TQCString&)
1070 {
1071  r_ef=s.latin1();
1072  e_ncCS=cachedCharset(Latin1);
1073 }
1074 
1075 
1076 TQString References::asUnicodeString()
1077 {
1078  return TQString::fromLatin1(r_ef);
1079 }
1080 
1081 
1082 int 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 
1097 TQCString References::first()
1098 {
1099  p_os=-1;
1100  return next();
1101 }
1102 
1103 
1104 TQCString 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 
1124 TQCString 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 
1146 void 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 
1199 void UserAgent::from7BitString(const TQCString &s)
1200 {
1201  u_agent=s;
1202  e_ncCS=cachedCharset(Latin1);
1203 }
1204 
1205 
1206 TQCString UserAgent::as7BitString(bool incType)
1207 {
1208  if(incType)
1209  return ( typeIntro()+u_agent );
1210  else
1211  return u_agent;
1212 }
1213 
1214 
1215 void 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 
1234 void 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 
1254 TQCString 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 
1263 void ContentType::fromUnicodeString(const TQString &s, const TQCString&)
1264 {
1265  from7BitString( TQCString(s.latin1()) );
1266 }
1267 
1268 
1269 TQString ContentType::asUnicodeString()
1270 {
1271  return TQString::fromLatin1(as7BitString(false));
1272 }
1273 
1274 
1275 TQCString 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 
1285 TQCString 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 
1295 void 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 
1307 bool ContentType::isMediatype(const char *s)
1308 {
1309  return ( strncasecmp(m_imeType.data(), s, strlen(s)) );
1310 }
1311 
1312 
1313 bool 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 
1324 bool ContentType::isText()
1325 {
1326  return (strncasecmp(m_imeType.data(), "text", 4)==0);
1327 }
1328 
1329 
1330 bool ContentType::isPlainText()
1331 {
1332  return (strcasecmp(m_imeType.data(), "text/plain")==0);
1333 }
1334 
1335 
1336 bool ContentType::isHTMLText()
1337 {
1338  return (strcasecmp(m_imeType.data(), "text/html")==0);
1339 }
1340 
1341 
1342 bool ContentType::isImage()
1343 {
1344  return (strncasecmp(m_imeType.data(), "image", 5)==0);
1345 }
1346 
1347 
1348 bool ContentType::isMultipart()
1349 {
1350  return (strncasecmp(m_imeType.data(), "multipart", 9)==0);
1351 }
1352 
1353 
1354 bool ContentType::isPartial()
1355 {
1356  return (strcasecmp(m_imeType.data(), "message/partial")==0);
1357 }
1358 
1359 
1360 TQCString 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 
1370 void ContentType::setCharset(const TQCString &s)
1371 {
1372  setParameter("charset", s);
1373 }
1374 
1375 
1376 TQCString ContentType::boundary()
1377 {
1378  return getParameter("boundary");
1379 }
1380 
1381 
1382 void ContentType::setBoundary(const TQCString &s)
1383 {
1384  setParameter("boundary", s, true);
1385 }
1386 
1387 
1388 TQString ContentType::name()
1389 {
1390  const char *dummy=0;
1391  return ( decodeRFC2047String(getParameter("name"), &dummy, defaultCS(), forceCS()) );
1392 }
1393 
1394 
1395 void 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 
1410 TQCString ContentType::id()
1411 {
1412  return (getParameter("id"));
1413 }
1414 
1415 
1416 void ContentType::setId(const TQCString &s)
1417 {
1418  setParameter("id", s, true);
1419 }
1420 
1421 
1422 int ContentType::partialNumber()
1423 {
1424  TQCString p=getParameter("number");
1425  if(!p.isEmpty())
1426  return p.toInt();
1427  else
1428  return -1;
1429 }
1430 
1431 
1432 int ContentType::partialCount()
1433 {
1434  TQCString p=getParameter("total");
1435  if(!p.isEmpty())
1436  return p.toInt();
1437  else
1438  return -1;
1439 }
1440 
1441 
1442 void 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 
1452 TQCString 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 
1468 void 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 
1497 typedef struct { const char *s; int e; } encTableType;
1498 
1499 static 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 
1508 void 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 
1523 TQCString 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 
1539 void CTEncoding::fromUnicodeString(const TQString &s, const TQCString&)
1540 {
1541  from7BitString( TQCString(s.latin1()) );
1542 }
1543 
1544 
1545 TQString CTEncoding::asUnicodeString()
1546 {
1547  return TQString::fromLatin1(as7BitString(false));
1548 }
1549 
1550 //-----</CTEncoding>---------------------------
1551 
1552 
1553 
1554 //-----<CDisposition>--------------------------
1555 
1556 void 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 
1573 TQCString 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 
1599 void 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 
1616 TQString 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 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.