24 #include <tdelocale.h>
26 #include <kmime_util.h>
49 bool insidequote =
false;
51 for (uint index=0; index<aStr.length(); index++) {
54 switch (aStr[index].latin1()) {
56 if (commentlevel == 0)
57 insidequote = !insidequote;
68 kdDebug(5300) <<
"Error in address splitting: Unmatched ')'"
79 if (!insidequote && (commentlevel == 0)) {
80 addr = aStr.mid(addrstart, index-addrstart);
82 list += addr.simplifyWhiteSpace();
89 if (!insidequote && (commentlevel == 0)) {
90 addr = aStr.mid(addrstart, aStr.length()-addrstart);
92 list += addr.simplifyWhiteSpace();
95 kdDebug(5300) <<
"Error in address splitting: "
96 <<
"Unexpected end of address list"
105 TQCString & displayName,
106 TQCString & addrSpec,
108 bool allowMultipleAddresses )
123 if ( address.isEmpty() )
124 return KPIM::AddressEmpty;
130 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
131 bool inQuotedString =
false;
132 int commentLevel = 0;
135 for (
const char* p = address.data(); *p && !stop; ++p ) {
139 case '"' : inQuotedString = !inQuotedString;
142 case '(' :
if ( !inQuotedString ) {
149 case '<' :
if ( !inQuotedString ) {
150 context = InAngleAddress;
161 return KPIM::UnexpectedEnd;
164 case ';' :
if ( !inQuotedString ) {
165 if ( allowMultipleAddresses )
168 return KPIM::UnexpectedComma;
173 default : dName += *p;
179 case '(' : ++commentLevel;
182 case ')' : --commentLevel;
183 if ( commentLevel == 0 ) {
196 return KPIM::UnexpectedEnd;
198 default : cmmt += *p;
202 case InAngleAddress : {
204 case '"' : inQuotedString = !inQuotedString;
207 case '>' :
if ( !inQuotedString ) {
219 return KPIM::UnexpectedEnd;
221 default : aSpec += *p;
228 if ( inQuotedString )
229 return KPIM::UnbalancedQuote;
230 if ( context == InComment )
231 return KPIM::UnbalancedParens;
232 if ( context == InAngleAddress )
233 return KPIM::UnclosedAngleAddr;
236 displayName = dName.stripWhiteSpace().latin1();
237 comment = cmmt.stripWhiteSpace().latin1();
238 addrSpec = aSpec.stripWhiteSpace().latin1();
240 if ( addrSpec.isEmpty() ) {
241 if ( displayName.isEmpty() )
242 return KPIM::NoAddressSpec;
244 addrSpec = displayName;
245 displayName.truncate( 0 );
253 return KPIM::AddressOk;
259 TQCString & displayName,
260 TQCString & addrSpec,
261 TQCString & comment )
263 return splitAddressInternal( address, displayName, addrSpec, comment,
270 TQString & displayName,
276 if ( result == AddressOk ) {
277 displayName = TQString::fromUtf8( d );
278 addrSpec = TQString::fromUtf8( a );
279 comment = TQString::fromUtf8( c );
290 if ( aStr.isEmpty() ) {
301 bool tooManyAtsFlag =
false;
303 int atCount = aStr.contains(
'@');
305 tooManyAtsFlag =
true;;
306 }
else if ( atCount == 0 ) {
313 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
314 bool inQuotedString =
false;
315 int commentLevel = 0;
317 unsigned int strlen = aStr.length();
319 for (
unsigned int index=0; index < strlen; index++ ) {
322 switch ( aStr[index].latin1() ) {
323 case '"' : inQuotedString = !inQuotedString;
326 if ( !inQuotedString ) {
332 if ( !inQuotedString ) {
333 return InvalidDisplayName;
337 if ( !inQuotedString ) {
338 return InvalidDisplayName;
342 if ( !inQuotedString ) {
343 return DisallowedChar;
347 if ( !inQuotedString ) {
348 context = InAngleAddress;
353 if (( index + 1 )> strlen ) {
354 return UnexpectedEnd;
359 if ( !inQuotedString )
360 return UnexpectedComma;
363 if ( !inQuotedString )
364 return UnbalancedParens;
367 if ( !inQuotedString )
368 return UnopenedAngleAddr;
371 if ( !inQuotedString ) {
373 return MissingLocalPart;
374 }
else if( index == strlen-1 ) {
375 return MissingDomainPart;
377 }
else if ( inQuotedString ) {
379 if ( atCount == 1 ) {
380 tooManyAtsFlag =
false;
388 switch ( aStr[index] ) {
389 case '(' : ++commentLevel;
391 case ')' : --commentLevel;
392 if ( commentLevel == 0 ) {
398 if (( index + 1 )> strlen ) {
399 return UnexpectedEnd;
406 case InAngleAddress : {
407 switch ( aStr[index] ) {
410 if ( !inQuotedString ) {
411 return UnexpectedComma;
414 case '"' : inQuotedString = !inQuotedString;
417 if ( inQuotedString ) {
419 if ( atCount == 1 ) {
420 tooManyAtsFlag =
false;
425 if ( !inQuotedString ) {
432 if (( index + 1 )> strlen ) {
433 return UnexpectedEnd;
442 if ( atCount == 0 && !inQuotedString )
445 if ( inQuotedString )
446 return UnbalancedQuote;
448 if ( context == InComment )
449 return UnbalancedParens;
451 if ( context == InAngleAddress )
452 return UnclosedAngleAddr;
454 if ( tooManyAtsFlag ) {
463 switch ( errorCode ) {
465 return i18n(
"The email address you entered is not valid because it "
466 "contains more than one @. "
467 "You will not create valid messages if you do not "
468 "change your address.");
470 return i18n(
"The email address you entered is not valid because it "
471 "does not contain a @."
472 "You will not create valid messages if you do not "
473 "change your address.");
475 return i18n(
"You have to enter something in the email address field.");
476 case MissingLocalPart :
477 return i18n(
"The email address you entered is not valid because it "
478 "does not contain a local part.");
479 case MissingDomainPart :
480 return i18n(
"The email address you entered is not valid because it "
481 "does not contain a domain part.");
482 case UnbalancedParens :
483 return i18n(
"The email address you entered is not valid because it "
484 "contains unclosed comments/brackets.");
486 return i18n(
"The email address you entered is valid.");
487 case UnclosedAngleAddr :
488 return i18n(
"The email address you entered is not valid because it "
489 "contains an unclosed anglebracket.");
490 case UnopenedAngleAddr :
491 return i18n(
"The email address you entered is not valid because it "
492 "contains an unopened anglebracket.");
493 case UnexpectedComma :
494 return i18n(
"The email address you have entered is not valid because it "
495 "contains an unexpected comma.");
497 return i18n(
"The email address you entered is not valid because it ended "
498 "unexpectedly, this probably means you have used an escaping type "
499 "character like an \\ as the last character in your email "
501 case UnbalancedQuote :
502 return i18n(
"The email address you entered is not valid because it "
503 "contains quoted text which does not end.");
505 return i18n(
"The email address you entered is not valid because it "
506 "does not seem to contain an actual email address, i.e. "
507 "something of the form joe@kde.org.");
508 case DisallowedChar :
509 return i18n(
"The email address you entered is not valid because it "
510 "contains an illegal character.");
511 case InvalidDisplayName :
512 return i18n(
"The email address you have entered is not valid because it "
513 "contains an invalid displayname.");
515 return i18n(
"Unknown problem with email address");
523 if ( aStr.isEmpty() ) {
527 int atChar = aStr.findRev(
'@' );
528 TQString domainPart = aStr.mid( atChar + 1);
529 TQString localPart = aStr.left( atChar );
530 bool tooManyAtsFlag =
false;
531 bool inQuotedString =
false;
532 int atCount = localPart.contains(
'@' );
534 unsigned int strlen = localPart.length();
535 for (
unsigned int index=0; index < strlen; index++ ) {
536 switch( localPart[ index ].latin1() ) {
537 case '"' : inQuotedString = !inQuotedString;
540 if ( inQuotedString ) {
542 if ( atCount == 0 ) {
543 tooManyAtsFlag =
false;
550 TQString addrRx =
"[a-zA-Z]*[~|{}`\\^?=/+*'&%$#!_\\w.-]*[~|{}`\\^?=/+*'&%$#!_a-zA-Z0-9-]@";
551 if ( localPart[ 0 ] ==
'\"' || localPart[ localPart.length()-1 ] ==
'\"' ) {
552 addrRx =
"\"[a-zA-Z@]*[\\w.@-]*[a-zA-Z0-9@]\"@";
554 if ( domainPart[ 0 ] ==
'[' || domainPart[ domainPart.length()-1 ] ==
']' ) {
555 addrRx +=
"\\[[0-9]{,3}(\\.[0-9]{,3}){3}\\]";
557 addrRx +=
"[\\w-]+(\\.[\\w-]+)*";
559 TQRegExp rx( addrRx );
560 return rx.exactMatch( aStr ) && !tooManyAtsFlag;
566 return i18n(
"The email address you entered is not valid because it "
567 "does not seem to contain an actual email address, i.e. "
568 "something of the form joe@kde.org.");
573 TQCString dummy1, dummy2, addrSpec;
575 splitAddressInternal( address, dummy1, addrSpec, dummy2,
577 if ( result != AddressOk ) {
578 addrSpec = TQCString();
580 <<
"Input: aStr\nError:"
598 TQCString dummy1, dummy2, addrSpec;
600 splitAddressInternal( addresses, dummy1, addrSpec, dummy2,
602 if ( result != AddressOk ) {
603 addrSpec = TQCString();
605 <<
"Input: aStr\nError:"
626 const int len=aStr.length();
627 const char cQuotes =
'"';
629 bool bInComment =
false;
630 bool bInQuotesOutsideOfEmail =
false;
631 int i=0, iAd=0, iMailStart=0, iMailEnd=0;
633 unsigned int commentstack = 0;
639 if(
'(' == c ) commentstack++;
640 if(
')' == c ) commentstack--;
641 bInComment = commentstack != 0;
642 if(
'"' == c && !bInComment )
643 bInQuotesOutsideOfEmail = !bInQuotesOutsideOfEmail;
645 if( !bInComment && !bInQuotesOutsideOfEmail ){
658 for( i = 0; len > i; ++i ) {
665 mail = aStr.mid( i+1 );
666 if ( mail.endsWith(
">" ) )
667 mail.truncate( mail.length() - 1 );
674 bInQuotesOutsideOfEmail =
false;
675 for( i = iAd-1; 0 <= i; --i ) {
679 if( !name.isEmpty() )
685 }
else if( bInQuotesOutsideOfEmail ){
687 bInQuotesOutsideOfEmail =
false;
688 else if ( c !=
'\\' )
697 bInQuotesOutsideOfEmail =
true;
707 if( !name.isEmpty() )
719 name = name.simplifyWhiteSpace();
720 mail = mail.simplifyWhiteSpace();
731 bInQuotesOutsideOfEmail =
false;
732 int parenthesesNesting = 0;
733 for( i = iAd+1; len > i; ++i ) {
737 if ( --parenthesesNesting == 0 ) {
739 if( !name.isEmpty() )
748 ++parenthesesNesting;
752 }
else if( bInQuotesOutsideOfEmail ){
754 bInQuotesOutsideOfEmail =
false;
755 else if ( c !=
'\\' )
764 bInQuotesOutsideOfEmail =
true;
773 if( !name.isEmpty() )
775 if ( ++parenthesesNesting > 0 )
787 name = name.simplifyWhiteSpace();
788 mail = mail.simplifyWhiteSpace();
790 return ! (name.isEmpty() || mail.isEmpty());
798 TQString e1Name, e1Email, e2Name, e2Email;
803 return e1Email == e2Email &&
804 ( !matchName || ( e1Name == e2Name ) );
810 const TQString & addrSpec,
811 const TQString & comment )
813 TQString realDisplayName = displayName;
814 realDisplayName.remove( TQChar( 0x202D ) );
815 realDisplayName.remove( TQChar( 0x202E ) );
816 realDisplayName.remove( TQChar( 0x202A ) );
817 realDisplayName.remove( TQChar( 0x202B ) );
819 if ( realDisplayName.isEmpty() && comment.isEmpty() )
821 else if ( comment.isEmpty() )
823 else if ( realDisplayName.isEmpty() ) {
824 TQString commentStr = comment;
828 return realDisplayName +
" (" + comment +
") <" + addrSpec +
">";
835 const int atPos = addrSpec.findRev(
'@' );
839 TQString idn = KIDNA::toUnicode( addrSpec.mid( atPos + 1 ) );
843 return addrSpec.left( atPos + 1 ) + idn;
850 const int atPos = addrSpec.findRev(
'@' );
854 TQString idn = KIDNA::toAscii( addrSpec.mid( atPos + 1 ) );
858 return addrSpec.left( atPos + 1 ) + idn;
871 TQStringList normalizedAddressList;
873 TQCString displayName, addrSpec, comment;
875 for( TQStringList::ConstIterator it = addressList.begin();
876 ( it != addressList.end() );
878 if( !(*it).isEmpty() ) {
882 displayName = KMime::decodeRFC2047String(displayName).utf8();
883 comment = KMime::decodeRFC2047String(comment).utf8();
885 normalizedAddressList <<
887 decodeIDN( TQString::fromUtf8( addrSpec ) ),
888 TQString::fromUtf8( comment ) );
891 kdDebug() <<
"splitting address failed: " << *it << endl;
900 return normalizedAddressList.join(
", " );
912 TQStringList normalizedAddressList;
914 TQCString displayName, addrSpec, comment;
916 for( TQStringList::ConstIterator it = addressList.begin();
917 ( it != addressList.end() );
919 if( !(*it).isEmpty() ) {
923 normalizedAddressList <<
925 encodeIDN( TQString::fromUtf8( addrSpec ) ),
926 TQString::fromUtf8( comment ) );
929 kdDebug() <<
"splitting address failed: " << *it << endl;
939 return normalizedAddressList.join(
", " );
945 static TQString escapeQuotes(
const TQString & str )
952 escaped.reserve( 2*str.length() );
953 unsigned int len = 0;
954 for (
unsigned int i = 0; i < str.length(); ++i, ++len ) {
955 if ( str[i] ==
'"' ) {
959 else if ( str[i] ==
'\\' ) {
963 if ( i >= str.length() )
966 escaped[len] = str[i];
968 escaped.truncate( len );
975 TQString quoted = str;
977 TQRegExp needQuotes(
"[^ 0-9A-Za-z\\x0080-\\xFFFF]" );
979 if ( ( quoted[0] ==
'"' ) && ( quoted[quoted.length() - 1] ==
'"' ) ) {
980 quoted =
"\"" + escapeQuotes( quoted.mid( 1, quoted.length() - 2 ) ) +
"\"";
982 else if ( quoted.find( needQuotes ) != -1 ) {
983 quoted =
"\"" + escapeQuotes( quoted ) +
"\"";