33 #include "kmime_header_parsing.h"
35 #include "kmime_codecs.h"
36 #include "kmime_util.h"
37 #include "kmime_warning.h"
39 #include <tdeglobal.h>
40 #include <kcharsets.h>
42 #include <tqtextcodec.h>
44 #include <tqcstring.h>
45 #include <tqstringlist.h>
50 using namespace KMime;
51 using namespace KMime::Types;
57 TQString AddrSpec::asString() const {
58 bool needsQuotes = false;
60 result.reserve( localPart.length() + domain.length() + 1 );
61 for ( unsigned int i = 0 ; i < localPart.length() ; ++i ) {
62 const char ch = localPart[i].latin1();
63 if ( ch == '.' || isAText( ch ) )
67 if ( ch == '\\' || ch == '"' )
73 return '"' + result + "\"@" + domain;
75 return result + '@' + domain;
80 namespace HeaderParsing {
83 bool parseEncodedWord( const char* & scursor, const char * const send,
84 TQString & result, TQCString & language ) {
87 assert( *(scursor-1) == '=' );
97 kdDebug() << "first" << endl;
98 KMIME_WARN_PREMATURE_END_OF(EncodedWord);
104 const char * charsetStart = scursor;
105 const char * languageStart = 0;
109 for ( ; scursor != send ; scursor++ )
110 if ( *scursor == '?')
112 else if ( *scursor == '*' && !languageStart )
113 languageStart = scursor + 1;
116 if ( scursor == send || *scursor != '?' ) {
117 kdDebug() << "second" << endl;
118 KMIME_WARN_PREMATURE_END_OF(EncodedWord);
124 TQCString maybeLanguage( languageStart, scursor - languageStart + 1 );
127 TQCString maybeCharset( charsetStart, ( languageStart ? languageStart : scursor + 1 ) - charsetStart );
137 const char * encodingStart = scursor;
140 for ( ; scursor != send ; scursor++ )
141 if ( *scursor == '?' ) break;
144 if ( scursor == send || *scursor != '?' ) {
145 kdDebug() << "third" << endl;
146 KMIME_WARN_PREMATURE_END_OF(EncodedWord);
151 TQCString maybeEncoding( encodingStart, scursor - encodingStart + 1 );
154 kdDebug() << "parseEncodedWord: found charset == \"" << maybeCharset
155 << "\"; language == \"" << maybeLanguage
156 << "\"; encoding == \"" << maybeEncoding << "\"" << endl;
166 const char * encodedTextStart = scursor;
169 for ( ; scursor != send ; scursor++ )
170 if ( *scursor == '?' ) break;
174 if ( scursor == send || *scursor != '?' ) {
175 kdDebug() << "fourth" << endl;
176 KMIME_WARN_PREMATURE_END_OF(EncodedWord);
181 if ( scursor == send || *scursor != '=' ) {
182 kdDebug() << "fifth" << endl;
183 KMIME_WARN_PREMATURE_END_OF(EncodedWord);
189 const char * const encodedTextEnd = scursor - 2;
198 Codec * codec = Codec::codecForName( maybeEncoding );
200 KMIME_WARN_UNKNOWN(Encoding,maybeEncoding);
205 Decoder * dec = codec->makeDecoder();
209 bool matchOK = false;
211 *textCodec = TDEGlobal::charsets()->codecForName( maybeCharset, matchOK );
213 if ( !matchOK || !textCodec ) {
214 KMIME_WARN_UNKNOWN(Charset,maybeCharset);
219 kdDebug() << "mimeName(): \"" << textCodec->mimeName() << "\"" << endl;
222 int encodedTextLength = encodedTextEnd - encodedTextStart;
223 TQByteArray buffer( codec->maxDecodedSizeFor( encodedTextLength ) );
224 TQByteArray::Iterator bit = buffer.begin();
225 TQByteArray::ConstIterator bend = buffer.end();
232 if ( !dec-> decode( encodedTextStart, encodedTextEnd, bit, bend ) )
233 KMIME_WARN << codec-> name() << " codec lies about it's maxDecodedSizeFor( "
234 << encodedTextLength << " )\nresult may be truncated" << endl;
236 result = textCodec->toUnicode( buffer.begin(), bit - buffer.begin() );
238 kdDebug() << "result now: \"" << result << "\"" << endl;
241 language = maybeLanguage;
246 static inline void eatWhiteSpace( const char* & scursor, const char * const send ) {
247 while ( scursor != send
248 && ( *scursor == ' ' || *scursor == '\n' ||
249 *scursor == '\t' || *scursor == '\r' ) )
253 bool parseAtom( const char * & scursor, const char * const send,
254 TQString & result, bool allow8Bit )
256 TQPair<const char*,int> maybeResult;
258 if ( parseAtom( scursor, send, maybeResult, allow8Bit ) ) {
259 result += TQString::fromLatin1( maybeResult.first, maybeResult.second );
266 bool parseAtom( const char * & scursor, const char * const send,
267 TQPair<const char*,int> & result, bool allow8Bit ) {
268 bool success = false;
269 const char * start = scursor;
271 while ( scursor != send ) {
272 signed char ch = *scursor++;
273 if ( ch > 0 && isAText(ch) ) {
276 } else if ( allow8Bit && ch < 0 ) {
288 result.first = start;
289 result.second = scursor - start;
293 bool parseToken( const char * & scursor, const char * const send,
294 TQString & result, bool allow8Bit )
296 TQPair<const char*,int> maybeResult;
298 if ( parseToken( scursor, send, maybeResult, allow8Bit ) ) {
299 result += TQString::fromLatin1( maybeResult.first, maybeResult.second );
306 bool parseToken( const char * & scursor, const char * const send,
307 TQPair<const char*,int> & result, bool allow8Bit )
309 bool success = false;
310 const char * start = scursor;
312 while ( scursor != send ) {
313 signed char ch = *scursor++;
314 if ( ch > 0 && isTText(ch) ) {
317 } else if ( allow8Bit && ch < 0 ) {
329 result.first = start;
330 result.second = scursor - start;
334 #define READ_ch_OR_FAIL if ( scursor == send ) { \
335 KMIME_WARN_PREMATURE_END_OF(GenericQuotedString); \
345 bool parseGenericQuotedString( const char* & scursor, const char * const send,
346 TQString & result, bool isCRLF,
347 const char openChar, const char closeChar )
356 assert( *(scursor-1) == openChar || *(scursor-1) == closeChar );
358 while ( scursor != send ) {
361 if ( ch == closeChar || ch == openChar ) {
371 KMIME_WARN_IF_8BIT(ch);
372 result += TQChar(ch);
386 result += TQChar( '\r');
392 if ( ch == ' ' || ch == '\t' ) {
396 result += TQChar(ch);
401 KMIME_WARN_NON_FOLDING(CRLF);
419 if ( !isCRLF && ( ch == ' ' || ch == '\t' ) ) {
422 result += TQChar(ch);
426 result += TQChar( '\n');
433 KMIME_WARN_IF_8BIT(ch);
434 result += TQChar(ch);
445 bool parseComment( const char* & scursor, const char * const send,
446 TQString & result, bool isCRLF, bool reallySave )
448 int commentNestingDepth = 1;
449 const char * afterLastClosingParenPos = 0;
451 const char * oldscursor = scursor;
453 assert( *(scursor-1) == '(' );
455 while ( commentNestingDepth ) {
457 if ( parseGenericQuotedString( scursor, send, cmntPart, isCRLF, '(', ')' ) ) {
458 assert( *(scursor-1) == ')' || *(scursor-1) == '(' );
461 switch ( *(scursor-1) ) {
467 if ( commentNestingDepth > 1 )
468 result += TQChar( ')');
469 maybeCmnt = TQString();
471 afterLastClosingParenPos = scursor;
472 --commentNestingDepth;
478 maybeCmnt += cmntPart;
479 maybeCmnt += TQChar( '(');
481 ++commentNestingDepth;
483 default: assert( 0 );
487 if ( afterLastClosingParenPos )
488 scursor = afterLastClosingParenPos;
490 scursor = oldscursor;
501 bool parsePhrase( const char* & scursor, const char * const send,
502 TQString & result, bool isCRLF )
504 enum { None, Phrase, Atom, EncodedWord, QuotedString } found = None;
507 const char * successfullyParsed = 0;
509 const char * oldscursor;
512 bool lastWasEncodedWord = false;
514 while ( scursor != send ) {
515 char ch = *scursor++;
518 if ( found == None ) {
522 if ( scursor != send && ( *scursor == ' ' || *scursor == '\t' ) )
526 successfullyParsed = scursor;
531 if ( parseGenericQuotedString( scursor, send, tmp, isCRLF, '"', '"' ) ) {
532 successfullyParsed = scursor;
533 assert( *(scursor-1) == '"' );
536 found = QuotedString;
543 result += TQChar( ' ');
548 lastWasEncodedWord = false;
554 if ( found == None ) {
557 result += TQChar( ' ');
566 if ( parseComment( scursor, send, tmp, isCRLF,
568 successfullyParsed = scursor;
569 lastWasEncodedWord = false;
574 scursor = successfullyParsed;
581 oldscursor = scursor;
583 if ( parseEncodedWord( scursor, send, tmp, lang ) ) {
584 successfullyParsed = scursor;
593 if ( !lastWasEncodedWord )
594 result += TQChar( ' ');
597 default: assert( 0 );
599 lastWasEncodedWord = true;
604 scursor = oldscursor;
610 if ( parseAtom( scursor, send, tmp, true ) ) {
611 successfullyParsed = scursor;
621 result += TQChar( ' ');
626 lastWasEncodedWord = false;
632 scursor = successfullyParsed;
637 eatWhiteSpace( scursor, send );
640 return ( found != None );
644 bool parseDotAtom( const char* & scursor, const char * const send,
645 TQString & result, bool isCRLF )
648 const char * successfullyParsed;
651 if ( !parseAtom( scursor, send, tmp, false ) )
654 successfullyParsed = scursor;
656 while ( scursor != send ) {
657 eatCFWS( scursor, send, isCRLF );
660 if ( scursor == send || *scursor != '.' ) return true;
663 eatCFWS( scursor, send, isCRLF );
665 if ( scursor == send || !isAText( *scursor ) ) {
669 scursor = successfullyParsed;
675 if ( !parseAtom( scursor, send, maybeAtom, false ) ) {
676 scursor = successfullyParsed;
680 result += TQChar( '.');
682 successfullyParsed = scursor;
685 scursor = successfullyParsed;
690 void eatCFWS( const char* & scursor, const char * const send, bool isCRLF ) {
693 while ( scursor != send ) {
694 const char * oldscursor = scursor;
696 char ch = *scursor++;
706 if ( parseComment( scursor, send, dummy, isCRLF, false ) )
708 scursor = oldscursor;
712 scursor = oldscursor;
719 bool parseDomain( const char* & scursor, const char * const send,
720 TQString & result, bool isCRLF ) {
721 eatCFWS( scursor, send, isCRLF );
722 if ( scursor == send ) return false;
730 if ( *scursor == '[' ) {
732 TQString maybeDomainLiteral;
735 while ( parseGenericQuotedString( scursor, send, maybeDomainLiteral,
736 isCRLF, '[', ']' ) ) {
737 if ( scursor == send ) {
739 if ( *(scursor-1) == ']' ) {
741 result = maybeDomainLiteral;
750 if ( *(scursor-1) == '[' ) {
751 maybeDomainLiteral += TQChar( '[');
755 result = maybeDomainLiteral;
760 TQString maybeDotAtom;
761 if ( parseDotAtom( scursor, send, maybeDotAtom, isCRLF ) ) {
762 result = maybeDotAtom;
769 bool parseObsRoute( const char* & scursor, const char* const send,
770 TQStringList & result, bool isCRLF, bool save ) {
771 while ( scursor != send ) {
772 eatCFWS( scursor, send, isCRLF );
773 if ( scursor == send ) return false;
776 if ( *scursor == ',' ) {
778 if ( save ) result.append( TQString() );
783 if ( *scursor == ':' ) {
785 if ( save ) result.append( TQString() );
790 if ( *scursor != '@' )
795 TQString maybeDomain;
796 if ( !parseDomain( scursor, send, maybeDomain, isCRLF ) ) return false;
797 if ( save ) result.append( maybeDomain );
800 eatCFWS( scursor, send, isCRLF );
801 if ( scursor == send ) return false;
802 if ( *scursor == ':' ) { scursor++; return true; }
803 if ( *scursor == ',' ) scursor++;
810 bool parseAddrSpec( const char* & scursor, const char * const send,
811 AddrSpec & result, bool isCRLF ) {
819 TQString maybeLocalPart;
822 while ( scursor != send ) {
824 eatCFWS( scursor, send, isCRLF );
826 char ch = *scursor++;
829 maybeLocalPart += TQChar( '.');
838 if ( parseGenericQuotedString( scursor, send, tmp, isCRLF, '"', '"' ) )
839 maybeLocalPart += tmp;
847 if ( parseAtom( scursor, send, tmp, false ) )
848 maybeLocalPart += tmp;
865 assert( *(scursor-1) == '@' );
867 TQString maybeDomain;
868 if ( !parseDomain( scursor, send, maybeDomain, isCRLF ) )
871 result.localPart = maybeLocalPart;
872 result.domain = maybeDomain;
878 bool parseAngleAddr( const char* & scursor, const char * const send,
879 AddrSpec & result, bool isCRLF ) {
881 eatCFWS( scursor, send, isCRLF );
882 if ( scursor == send || *scursor != '<' ) return false;
885 eatCFWS( scursor, send, isCRLF );
886 if ( scursor == send ) return false;
888 if ( *scursor == '@' || *scursor == ',' ) {
890 KMIME_WARN << "obsolete source route found! ignoring." << endl;
892 if ( !parseObsRoute( scursor, send, dummy,
896 if ( scursor == send ) return false;
900 AddrSpec maybeAddrSpec;
901 if ( !parseAddrSpec( scursor, send, maybeAddrSpec, isCRLF ) ) return false;
903 eatCFWS( scursor, send, isCRLF );
904 if ( scursor == send || *scursor != '>' ) return false;
907 result = maybeAddrSpec;
912 bool parseMailbox( const char* & scursor, const char * const send,
913 Mailbox & result, bool isCRLF ) {
921 eatCFWS( scursor, send, isCRLF );
922 if ( scursor == send ) return false;
924 AddrSpec maybeAddrSpec;
927 const char * oldscursor = scursor;
928 if ( parseAddrSpec( scursor, send, maybeAddrSpec, isCRLF ) ) {
929 result.displayName = TQString();
930 result.addrSpec = maybeAddrSpec;
933 scursor = oldscursor;
936 TQString maybeDisplayName;
937 if ( !parsePhrase( scursor, send, maybeDisplayName, isCRLF ) ) {
939 maybeDisplayName = TQString();
940 scursor = oldscursor;
943 eatCFWS( scursor, send, isCRLF );
944 if ( scursor == send ) return false;
948 if ( !parseAngleAddr( scursor, send, maybeAddrSpec, isCRLF ) )
951 if ( maybeDisplayName.isNull() ) {
953 eatWhiteSpace( scursor, send );
954 if ( scursor != send && *scursor == '(' ) {
956 if ( !parseComment( scursor, send, maybeDisplayName, isCRLF, true ) )
961 result.displayName = maybeDisplayName;
962 result.addrSpec = maybeAddrSpec;
966 bool parseGroup( const char* & scursor, const char * const send,
967 Address & result, bool isCRLF ) {
973 eatCFWS( scursor, send, isCRLF );
974 if ( scursor == send ) return false;
977 TQString maybeDisplayName;
978 if ( !parsePhrase( scursor, send, maybeDisplayName, isCRLF ) )
982 eatCFWS( scursor, send, isCRLF );
983 if ( scursor == send || *scursor != ':' ) return false;
985 result.displayName = maybeDisplayName;
989 while ( scursor != send ) {
990 eatCFWS( scursor, send, isCRLF );
991 if ( scursor == send ) return false;
994 if ( *scursor == ',' ) { scursor++; continue; }
997 if ( *scursor == ';' ) { scursor++; return true; }
999 Mailbox maybeMailbox;
1000 if ( !parseMailbox( scursor, send, maybeMailbox, isCRLF ) )
1002 result.mailboxList.append( maybeMailbox );
1004 eatCFWS( scursor, send, isCRLF );
1006 if ( scursor == send ) return false;
1008 if ( *scursor == ';' ) { scursor++; return true; }
1010 if ( *scursor == ',' ) scursor++;
1016 bool parseAddress( const char* & scursor, const char * const send,
1017 Address & result, bool isCRLF ) {
1020 eatCFWS( scursor, send, isCRLF );
1021 if ( scursor == send ) return false;
1024 Mailbox maybeMailbox;
1025 const char * oldscursor = scursor;
1026 if ( parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) {
1028 result.displayName = TQString();
1029 result.mailboxList.append( maybeMailbox );
1032 scursor = oldscursor;
1034 Address maybeAddress;
1037 if ( !parseGroup( scursor, send, maybeAddress, isCRLF ) )
1040 result = maybeAddress;
1044 bool parseAddressList( const char* & scursor, const char * const send,
1045 AddressList & result, bool isCRLF ) {
1046 while ( scursor != send ) {
1047 eatCFWS( scursor, send, isCRLF );
1049 if ( scursor == send ) return true;
1051 if ( *scursor == ',' ) { scursor++; continue; }
1054 Address maybeAddress;
1055 if ( !parseAddress( scursor, send, maybeAddress, isCRLF ) ) return false;
1056 result.append( maybeAddress );
1058 eatCFWS( scursor, send, isCRLF );
1060 if ( scursor == send ) return true;
1062 if ( *scursor == ',' ) scursor++;
1068 static TQString asterisk = TQString::fromLatin1( "*0*",1);
1069 static TQString asteriskZero = TQString::fromLatin1( "*0*",2);
1072 bool parseParameter( const char* & scursor, const char * const send,
1073 TQPair<TQString,TQStringOrTQPair> & result, bool isCRLF ) {
1084 eatCFWS( scursor, send, isCRLF );
1085 if ( scursor == send ) return false;
1090 TQString maybeAttribute;
1091 if ( !parseToken( scursor, send, maybeAttribute, false ) )
1094 eatCFWS( scursor, send, isCRLF );
1096 if ( scursor == send || *scursor != '=' ) return false;
1099 eatCFWS( scursor, send, isCRLF );
1100 if ( scursor == send ) {
1102 if ( maybeAttribute.endsWith( asterisk ) ) {
1103 KMIME_WARN << "attribute ends with \"*\", but value is empty! "
1104 "Chopping away \"*\"." << endl;
1105 maybeAttribute.truncate( maybeAttribute.length() - 1 );
1107 result = qMakePair( maybeAttribute.lower(), TQStringOrTQPair() );
1111 const char * oldscursor = scursor;
1116 TQStringOrTQPair maybeValue;
1117 if ( *scursor == '"' ) {
1120 if ( maybeAttribute.endsWith( asterisk ) ) {
1124 KMIME_WARN << "attribute ends with \"*\", but value is a quoted-string! "
1125 "Chopping away \"*\"." << endl;
1126 maybeAttribute.truncate( maybeAttribute.length() - 1 );
1129 if ( !parseGenericQuotedString( scursor, send, maybeValue.qstring, isCRLF ) ) {
1130 scursor = oldscursor;
1131 result = qMakePair( maybeAttribute.lower(), TQStringOrTQPair() );
1136 if ( !parseToken( scursor, send, maybeValue.qpair, false ) ) {
1137 scursor = oldscursor;
1138 result = qMakePair( maybeAttribute.lower(), TQStringOrTQPair() );
1143 result = qMakePair( maybeAttribute.lower(), maybeValue );
1149 bool parseRawParameterList( const char* & scursor, const char * const send,
1150 TQMap<TQString,TQStringOrTQPair> & result,
1162 while ( scursor != send ) {
1163 eatCFWS( scursor, send, isCRLF );
1165 if ( scursor == send ) return true;
1167 if ( *scursor == ';' ) { scursor++; continue; }
1169 TQPair<TQString,TQStringOrTQPair> maybeParameter;
1170 if ( !parseParameter( scursor, send, maybeParameter, isCRLF ) ) {
1178 if ( maybeParameter.first.isNull() ) return false;
1179 while ( scursor != send ) {
1180 if ( *scursor++ == ';' ) goto IS_SEMICOLON;
1189 result.insert( maybeParameter.first, maybeParameter.second );
1191 eatCFWS( scursor, send, isCRLF );
1193 if ( scursor == send ) return true;
1195 if ( *scursor == ';' ) scursor++;
1201 static void decodeRFC2231Value( Codec* & rfc2231Codec,
1202 TQTextCodec* & textcodec,
1203 bool isContinuation, TQString & value,
1204 TQPair<const char*,int> & source ) {
1210 const char * decBegin = source.first;
1211 const char * decCursor = decBegin;
1212 const char * decEnd = decCursor + source.second;
1214 if ( !isContinuation ) {
1216 while ( decCursor != decEnd ) {
1217 if ( *decCursor == '\'' ) break;
1221 if ( decCursor == decEnd ) {
1224 KMIME_WARN << "No charset in extended-initial-value. "
1225 "Assuming \"iso-8859-1\"." << endl;
1226 value += TQString::fromLatin1( decBegin, source.second );
1230 TQCString charset( decBegin, decCursor - decBegin + 1 );
1232 const char * oldDecCursor = ++decCursor;
1234 while ( decCursor != decEnd ) {
1235 if ( *decCursor == '\'' ) break;
1238 if ( decCursor == decEnd ) {
1239 KMIME_WARN << "No language in extended-initial-value. "
1240 "Trying to recover." << endl;
1241 decCursor = oldDecCursor;
1252 bool matchOK = false;
1253 textcodec = TDEGlobal::charsets()->codecForName( charset, matchOK );
1256 KMIME_WARN_UNKNOWN(Charset,charset);
1260 if ( !rfc2231Codec ) {
1261 rfc2231Codec = Codec::codecForName( "x-kmime-rfc2231");
1262 assert( rfc2231Codec );
1266 value += TQString::fromLatin1( decCursor, decEnd - decCursor );
1270 Decoder * dec = rfc2231Codec->makeDecoder();
1277 TQByteArray buffer( rfc2231Codec->maxDecodedSizeFor( decEnd - decCursor ) );
1278 TQByteArray::Iterator bit = buffer.begin();
1279 TQByteArray::ConstIterator bend = buffer.end();
1281 if ( !dec-> decode( decCursor, decEnd, bit, bend ) )
1282 KMIME_WARN << rfc2231Codec-> name()
1283 << " codec lies about it's maxDecodedSizeFor()\n"
1284 "result may be truncated" << endl;
1286 value += textcodec->toUnicode( buffer.begin(), bit - buffer.begin() );
1288 kdDebug() << "value now: \"" << value << "\"" << endl;
1297 bool parseParameterList( const char* & scursor, const char * const send,
1298 TQMap<TQString,TQString> & result, bool isCRLF ) {
1300 TQMap<TQString,TQStringOrTQPair> rawParameterList;
1301 if (!parseRawParameterList( scursor, send, rawParameterList, isCRLF ) )
1304 if ( rawParameterList.isEmpty() ) return true;
1311 Codec * rfc2231Codec = 0;
1312 TQTextCodec * textcodec = 0;
1315 enum Modes { NoMode = 0x0, Continued = 0x1, Encoded = 0x2 } mode;
1317 TQMapIterator<TQString,TQStringOrTQPair> it, end = rawParameterList.end();
1319 for ( it = rawParameterList.begin() ; it != end ; ++it ) {
1320 if ( attribute.isNull() || !it.key().startsWith( attribute ) ) {
1326 if ( !attribute.isNull() ) result.insert( attribute, value );
1329 attribute = it.key();
1332 if ( attribute.endsWith( asterisk ) ) {
1333 attribute.truncate( attribute.length() - 1 );
1334 mode = (Modes) (( int) mode | Encoded);
1337 if ( attribute.endsWith( asteriskZero ) ) {
1338 attribute.truncate( attribute.length() - 2 );
1339 mode = (Modes) (( int) mode | Continued);
1344 if ( mode & Encoded ) {
1345 decodeRFC2231Value( rfc2231Codec, textcodec,
1347 value, (*it).qpair );
1350 if ( (*it).qpair.first )
1351 value += TQString::fromLatin1( (*it).qpair.first, (*it).qpair.second );
1353 value += (*it).qstring;
1360 if ( !(mode & Continued) ) {
1362 result.insert( attribute, value );
1364 attribute = TQString();
1372 if ( it.key().endsWith( asterisk ) ) {
1374 decodeRFC2231Value( rfc2231Codec, textcodec,
1376 value, (*it).qpair );
1379 if ( (*it).qpair.first )
1380 value += TQString::fromLatin1( (*it).qpair.first, (*it).qpair.second );
1382 value += (*it).qstring;
1388 if ( !attribute.isNull() )
1389 result.insert( attribute, value );
1394 static const char * stdDayNames[] = {
1395 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1397 static const int stdDayNamesLen = sizeof stdDayNames / sizeof *stdDayNames;
1399 static bool parseDayName( const char* & scursor, const char * const send )
1402 if ( send - scursor < 3 ) return false;
1404 for ( int i = 0 ; i < stdDayNamesLen ; ++i )
1405 if ( tqstrnicmp( scursor, stdDayNames[i], 3 ) == 0 ) {
1407 kdDebug() << "found " << stdDayNames[i] << endl;
1415 static const char * stdMonthNames[] = {
1416 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1417 "Jul", "Aug", "Sep", "Oct", "Nov", "Dez"
1419 static const int stdMonthNamesLen =
1420 sizeof stdMonthNames / sizeof *stdMonthNames;
1422 static bool parseMonthName( const char* & scursor, const char * const send,
1426 if ( send - scursor < 3 ) return false;
1428 for ( result = 0 ; result < stdMonthNamesLen ; ++result )
1429 if ( tqstrnicmp( scursor, stdMonthNames[result], 3 ) == 0 ) {
1438 static const struct {
1439 const char * tzName;
1440 long int secsEastOfGMT;
1487 static const int timeZonesLen = sizeof timeZones / sizeof *timeZones;
1489 static bool parseAlphaNumericTimeZone( const char* & scursor,
1490 const char * const send,
1491 long int & secsEastOfGMT,
1492 bool & timeZoneKnown )
1494 TQPair<const char*,int> maybeTimeZone(0,0);
1495 if ( !parseToken( scursor, send, maybeTimeZone, false ) )
1497 for ( int i = 0 ; i < timeZonesLen ; ++i )
1498 if ( tqstrnicmp( timeZones[i].tzName,
1499 maybeTimeZone.first, maybeTimeZone.second ) == 0 ) {
1500 scursor += maybeTimeZone.second;
1501 secsEastOfGMT = timeZones[i].secsEastOfGMT;
1502 timeZoneKnown = true;
1507 KMIME_WARN_UNKNOWN(time zone,TQCString( maybeTimeZone.first, maybeTimeZone.second+1 ));
1509 timeZoneKnown = false;
1514 static int parseDigits( const char* & scursor, const char * const send,
1519 for ( ; scursor != send && isdigit( *scursor ) ; scursor++, digits++ ) {
1521 result += int( *scursor - '0' );
1526 static bool parseTimeOfDay( const char* & scursor, const char * const send,
1527 int & hour, int & min, int & sec, bool isCRLF= false )
1534 if ( !parseDigits( scursor, send, hour ) ) return false;
1536 eatCFWS( scursor, send, isCRLF );
1537 if ( scursor == send || *scursor != ':' ) return false;
1540 eatCFWS( scursor, send, isCRLF );
1541 if ( scursor == send ) return false;
1546 if ( !parseDigits( scursor, send, min ) ) return false;
1548 eatCFWS( scursor, send, isCRLF );
1549 if ( scursor == send ) return true;
1554 if ( *scursor == ':' ) {
1557 eatCFWS( scursor, send, isCRLF );
1558 if ( scursor == send ) return false;
1560 if ( !parseDigits( scursor, send, sec ) ) return false;
1569 bool parseTime( const char* & scursor, const char * send,
1570 int & hour, int & min, int & sec, long int & secsEastOfGMT,
1571 bool & timeZoneKnown, bool isCRLF )
1583 eatCFWS( scursor, send, isCRLF );
1584 if ( scursor == send ) return false;
1586 if ( !parseTimeOfDay( scursor, send, hour, min, sec, isCRLF ) )
1589 eatCFWS( scursor, send, isCRLF );
1590 if ( scursor == send ) {
1591 timeZoneKnown = false;
1596 timeZoneKnown = true;
1597 if ( *scursor == '+' || *scursor == '-' ) {
1599 const char sign = *scursor++;
1602 if ( parseDigits( scursor, send, maybeTimeZone ) != 4 ) return false;
1603 secsEastOfGMT = 60 * ( maybeTimeZone / 100 * 60 + maybeTimeZone % 100 );
1604 if ( sign == '-' ) {
1605 secsEastOfGMT *= -1;
1606 if ( secsEastOfGMT == 0 )
1607 timeZoneKnown = false;
1611 if ( !parseAlphaNumericTimeZone( scursor, send, secsEastOfGMT, timeZoneKnown ) )
1618 bool parseDateTime( const char* & scursor, const char * const send,
1619 Types::DateTime & result, bool isCRLF )
1631 struct tm maybeDateTime = {
1632 #ifdef HAVE_TM_GMTOFF
1635 0, 0, 0, 0, 0, 0, 0, 0, 0
1638 eatCFWS( scursor, send, isCRLF );
1639 if ( scursor == send ) return false;
1644 if ( parseDayName( scursor, send ) ) {
1645 eatCFWS( scursor, send, isCRLF );
1646 if ( scursor == send ) return false;
1648 if ( *scursor == ',' ) {
1650 eatCFWS( scursor, send, isCRLF );
1658 if ( !parseDigits( scursor, send, maybeDay ) ) return false;
1660 eatCFWS( scursor, send, isCRLF );
1661 if ( scursor == send ) return false;
1664 maybeDateTime.tm_mday = maybeDay;
1670 if ( !parseMonthName( scursor, send, maybeMonth ) ) return false;
1671 if ( scursor == send ) return false;
1672 assert( maybeMonth >= 0 ); assert( maybeMonth <= 11 );
1674 eatCFWS( scursor, send, isCRLF );
1675 if ( scursor == send ) return false;
1678 maybeDateTime.tm_mon = maybeMonth;
1684 if ( !parseDigits( scursor, send, maybeYear ) ) return false;
1686 if ( maybeYear < 50 )
1688 else if ( maybeYear < 1000 )
1691 if ( maybeYear < 1900 ) return false;
1693 eatCFWS( scursor, send, isCRLF );
1694 if ( scursor == send ) return false;
1697 maybeDateTime.tm_year = maybeYear - 1900;
1702 int maybeHour, maybeMinute, maybeSecond;
1703 long int secsEastOfGMT;
1704 bool timeZoneKnown = true;
1706 if ( !parseTime( scursor, send,
1707 maybeHour, maybeMinute, maybeSecond,
1708 secsEastOfGMT, timeZoneKnown, isCRLF ) )
1712 maybeDateTime.tm_hour = maybeHour;
1713 maybeDateTime.tm_min = maybeMinute;
1714 maybeDateTime.tm_sec = maybeSecond;
1715 maybeDateTime.tm_isdst = DateFormatter::isDaylight();
1717 result.time = mktime( &maybeDateTime );
1718 if ( result.time == (time_t)(-1) ) return false;
1722 result.secsEastOfGMT = secsEastOfGMT;
1723 result.timeZoneKnown = timeZoneKnown;
1729 bool tryToMakeAnySenseOfDateString( const char* & scursor,
1730 const char * const send,
1731 time_t & result, bool isCRLF )
Abstract base class of codecs like base64 and quoted-printable.
virtual const char * name() const =0
Stateful decoder class, modelled after TQTextDecoder.
virtual bool decode(const char *&scursor, const char *const send, char *&dcursor, const char *const dend)=0 Decode a chunk of data, maintaining state information between calls.
|