23 #include <tdelocale.h>
25 #include <kmime_util.h>
48 bool insidequote =
false;
50 for (uint index=0; index<aStr.length(); index++) {
53 switch (aStr[index].latin1()) {
55 if (commentlevel == 0)
56 insidequote = !insidequote;
67 kdDebug(5300) <<
"Error in address splitting: Unmatched ')'"
78 if (!insidequote && (commentlevel == 0)) {
79 addr = aStr.mid(addrstart, index-addrstart);
81 list += addr.simplifyWhiteSpace();
88 if (!insidequote && (commentlevel == 0)) {
89 addr = aStr.mid(addrstart, aStr.length()-addrstart);
91 list += addr.simplifyWhiteSpace();
94 kdDebug(5300) <<
"Error in address splitting: "
95 <<
"Unexpected end of address list"
104 TQCString & displayName,
105 TQCString & addrSpec,
107 bool allowMultipleAddresses )
122 if ( address.isEmpty() )
123 return KPIM::AddressEmpty;
129 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
130 bool inQuotedString =
false;
131 int commentLevel = 0;
134 for (
const char* p = address.data(); *p && !stop; ++p ) {
138 case '"' : inQuotedString = !inQuotedString;
141 case '(' :
if ( !inQuotedString ) {
148 case '<' :
if ( !inQuotedString ) {
149 context = InAngleAddress;
160 return KPIM::UnexpectedEnd;
163 case ';' :
if ( !inQuotedString ) {
164 if ( allowMultipleAddresses )
167 return KPIM::UnexpectedComma;
172 default : dName += *p;
178 case '(' : ++commentLevel;
181 case ')' : --commentLevel;
182 if ( commentLevel == 0 ) {
195 return KPIM::UnexpectedEnd;
197 default : cmmt += *p;
201 case InAngleAddress : {
203 case '"' : inQuotedString = !inQuotedString;
206 case '>' :
if ( !inQuotedString ) {
218 return KPIM::UnexpectedEnd;
220 default : aSpec += *p;
227 if ( inQuotedString )
228 return KPIM::UnbalancedQuote;
229 if ( context == InComment )
230 return KPIM::UnbalancedParens;
231 if ( context == InAngleAddress )
232 return KPIM::UnclosedAngleAddr;
235 displayName = dName.stripWhiteSpace().latin1();
236 comment = cmmt.stripWhiteSpace().latin1();
237 addrSpec = aSpec.stripWhiteSpace().latin1();
239 if ( addrSpec.isEmpty() ) {
240 if ( displayName.isEmpty() )
241 return KPIM::NoAddressSpec;
243 addrSpec = displayName;
244 displayName.truncate( 0 );
252 return KPIM::AddressOk;
258 TQCString & displayName,
259 TQCString & addrSpec,
260 TQCString & comment )
262 return splitAddressInternal( address, displayName, addrSpec, comment,
269 TQString & displayName,
275 if ( result == AddressOk ) {
276 displayName = TQString::fromUtf8( d );
277 addrSpec = TQString::fromUtf8( a );
278 comment = TQString::fromUtf8( c );
289 if ( aStr.isEmpty() ) {
300 bool tooManyAtsFlag =
false;
302 int atCount = aStr.contains(
'@');
304 tooManyAtsFlag =
true;;
305 }
else if ( atCount == 0 ) {
312 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
313 bool inQuotedString =
false;
314 int commentLevel = 0;
316 unsigned int strlen = aStr.length();
318 for (
unsigned int index=0; index < strlen; index++ ) {
321 switch ( aStr[index].latin1() ) {
322 case '"' : inQuotedString = !inQuotedString;
325 if ( !inQuotedString ) {
331 if ( !inQuotedString ) {
332 return InvalidDisplayName;
336 if ( !inQuotedString ) {
337 return InvalidDisplayName;
341 if ( !inQuotedString ) {
342 return DisallowedChar;
346 if ( !inQuotedString ) {
347 context = InAngleAddress;
352 if (( index + 1 )> strlen ) {
353 return UnexpectedEnd;
358 if ( !inQuotedString )
359 return UnexpectedComma;
362 if ( !inQuotedString )
363 return UnbalancedParens;
366 if ( !inQuotedString )
367 return UnopenedAngleAddr;
370 if ( !inQuotedString ) {
372 return MissingLocalPart;
373 }
else if( index == strlen-1 ) {
374 return MissingDomainPart;
376 }
else if ( inQuotedString ) {
378 if ( atCount == 1 ) {
379 tooManyAtsFlag =
false;
387 switch ( aStr[index] ) {
388 case '(' : ++commentLevel;
390 case ')' : --commentLevel;
391 if ( commentLevel == 0 ) {
397 if (( index + 1 )> strlen ) {
398 return UnexpectedEnd;
405 case InAngleAddress : {
406 switch ( aStr[index] ) {
409 if ( !inQuotedString ) {
410 return UnexpectedComma;
413 case '"' : inQuotedString = !inQuotedString;
416 if ( inQuotedString ) {
418 if ( atCount == 1 ) {
419 tooManyAtsFlag =
false;
424 if ( !inQuotedString ) {
431 if (( index + 1 )> strlen ) {
432 return UnexpectedEnd;
441 if ( atCount == 0 && !inQuotedString )
444 if ( inQuotedString )
445 return UnbalancedQuote;
447 if ( context == InComment )
448 return UnbalancedParens;
450 if ( context == InAngleAddress )
451 return UnclosedAngleAddr;
453 if ( tooManyAtsFlag ) {
462 switch ( errorCode ) {
464 return i18n(
"The email address you entered is not valid because it "
465 "contains more than one @. "
466 "You will not create valid messages if you do not "
467 "change your address.");
469 return i18n(
"The email address you entered is not valid because it "
470 "does not contain a @."
471 "You will not create valid messages if you do not "
472 "change your address.");
474 return i18n(
"You have to enter something in the email address field.");
475 case MissingLocalPart :
476 return i18n(
"The email address you entered is not valid because it "
477 "does not contain a local part.");
478 case MissingDomainPart :
479 return i18n(
"The email address you entered is not valid because it "
480 "does not contain a domain part.");
481 case UnbalancedParens :
482 return i18n(
"The email address you entered is not valid because it "
483 "contains unclosed comments/brackets.");
485 return i18n(
"The email address you entered is valid.");
486 case UnclosedAngleAddr :
487 return i18n(
"The email address you entered is not valid because it "
488 "contains an unclosed anglebracket.");
489 case UnopenedAngleAddr :
490 return i18n(
"The email address you entered is not valid because it "
491 "contains an unopened anglebracket.");
492 case UnexpectedComma :
493 return i18n(
"The email address you have entered is not valid because it "
494 "contains an unexpected comma.");
496 return i18n(
"The email address you entered is not valid because it ended "
497 "unexpectedly, this probably means you have used an escaping type "
498 "character like an \\ as the last character in your email "
500 case UnbalancedQuote :
501 return i18n(
"The email address you entered is not valid because it "
502 "contains quoted text which does not end.");
504 return i18n(
"The email address you entered is not valid because it "
505 "does not seem to contain an actual email address, i.e. "
506 "something of the form joe@kde.org.");
507 case DisallowedChar :
508 return i18n(
"The email address you entered is not valid because it "
509 "contains an illegal character.");
510 case InvalidDisplayName :
511 return i18n(
"The email address you have entered is not valid because it "
512 "contains an invalid displayname.");
514 return i18n(
"Unknown problem with email address");
522 if ( aStr.isEmpty() ) {
526 int atChar = aStr.findRev(
'@' );
527 TQString domainPart = aStr.mid( atChar + 1);
528 TQString localPart = aStr.left( atChar );
529 bool tooManyAtsFlag =
false;
530 bool inQuotedString =
false;
531 int atCount = localPart.contains(
'@' );
533 unsigned int strlen = localPart.length();
534 for (
unsigned int index=0; index < strlen; index++ ) {
535 switch( localPart[ index ].latin1() ) {
536 case '"' : inQuotedString = !inQuotedString;
539 if ( inQuotedString ) {
541 if ( atCount == 0 ) {
542 tooManyAtsFlag =
false;
549 TQString addrRx =
"[a-zA-Z]*[~|{}`\\^?=/+*'&%$#!_\\w.-]*[~|{}`\\^?=/+*'&%$#!_a-zA-Z0-9-]@";
550 if ( localPart[ 0 ] ==
'\"' || localPart[ localPart.length()-1 ] ==
'\"' ) {
551 addrRx =
"\"[a-zA-Z@]*[\\w.@-]*[a-zA-Z0-9@]\"@";
553 if ( domainPart[ 0 ] ==
'[' || domainPart[ domainPart.length()-1 ] ==
']' ) {
554 addrRx +=
"\\[[0-9]{,3}(\\.[0-9]{,3}){3}\\]";
556 addrRx +=
"[\\w-]+(\\.[\\w-]+)*";
558 TQRegExp rx( addrRx );
559 return rx.exactMatch( aStr ) && !tooManyAtsFlag;
565 return i18n(
"The email address you entered is not valid because it "
566 "does not seem to contain an actual email address, i.e. "
567 "something of the form joe@kde.org.");
572 TQCString dummy1, dummy2, addrSpec;
574 splitAddressInternal( address, dummy1, addrSpec, dummy2,
576 if ( result != AddressOk ) {
577 addrSpec = TQCString();
579 <<
"Input: aStr\nError:"
597 TQCString dummy1, dummy2, addrSpec;
599 splitAddressInternal( addresses, dummy1, addrSpec, dummy2,
601 if ( result != AddressOk ) {
602 addrSpec = TQCString();
604 <<
"Input: aStr\nError:"
625 const int len=aStr.length();
626 const char cQuotes =
'"';
628 bool bInComment =
false;
629 bool bInQuotesOutsideOfEmail =
false;
630 int i=0, iAd=0, iMailStart=0, iMailEnd=0;
632 unsigned int commentstack = 0;
638 if(
'(' == c ) commentstack++;
639 if(
')' == c ) commentstack--;
640 bInComment = commentstack != 0;
641 if(
'"' == c && !bInComment )
642 bInQuotesOutsideOfEmail = !bInQuotesOutsideOfEmail;
644 if( !bInComment && !bInQuotesOutsideOfEmail ){
657 for( i = 0; len > i; ++i ) {
664 mail = aStr.mid( i+1 );
665 if ( mail.endsWith(
">" ) )
666 mail.truncate( mail.length() - 1 );
673 bInQuotesOutsideOfEmail =
false;
674 for( i = iAd-1; 0 <= i; --i ) {
678 if( !name.isEmpty() )
684 }
else if( bInQuotesOutsideOfEmail ){
686 bInQuotesOutsideOfEmail =
false;
687 else if ( c !=
'\\' )
696 bInQuotesOutsideOfEmail =
true;
706 if( !name.isEmpty() )
718 name = name.simplifyWhiteSpace();
719 mail = mail.simplifyWhiteSpace();
730 bInQuotesOutsideOfEmail =
false;
731 int parenthesesNesting = 0;
732 for( i = iAd+1; len > i; ++i ) {
736 if ( --parenthesesNesting == 0 ) {
738 if( !name.isEmpty() )
747 ++parenthesesNesting;
751 }
else if( bInQuotesOutsideOfEmail ){
753 bInQuotesOutsideOfEmail =
false;
754 else if ( c !=
'\\' )
763 bInQuotesOutsideOfEmail =
true;
772 if( !name.isEmpty() )
774 if ( ++parenthesesNesting > 0 )
786 name = name.simplifyWhiteSpace();
787 mail = mail.simplifyWhiteSpace();
789 return ! (name.isEmpty() || mail.isEmpty());
797 TQString e1Name, e1Email, e2Name, e2Email;
802 return e1Email == e2Email &&
803 ( !matchName || ( e1Name == e2Name ) );
809 const TQString & addrSpec,
810 const TQString & comment )
812 TQString realDisplayName = displayName;
813 realDisplayName.remove( TQChar( 0x202D ) );
814 realDisplayName.remove( TQChar( 0x202E ) );
815 realDisplayName.remove( TQChar( 0x202A ) );
816 realDisplayName.remove( TQChar( 0x202B ) );
818 if ( realDisplayName.isEmpty() && comment.isEmpty() )
820 else if ( comment.isEmpty() )
822 else if ( realDisplayName.isEmpty() ) {
823 TQString commentStr = comment;
827 return realDisplayName +
" (" + comment +
") <" + addrSpec +
">";
834 const int atPos = addrSpec.findRev(
'@' );
838 TQString idn = KIDNA::toUnicode( addrSpec.mid( atPos + 1 ) );
842 return addrSpec.left( atPos + 1 ) + idn;
849 const int atPos = addrSpec.findRev(
'@' );
853 TQString idn = KIDNA::toAscii( addrSpec.mid( atPos + 1 ) );
857 return addrSpec.left( atPos + 1 ) + idn;
870 TQStringList normalizedAddressList;
872 TQCString displayName, addrSpec, comment;
874 for( TQStringList::ConstIterator it = addressList.begin();
875 ( it != addressList.end() );
877 if( !(*it).isEmpty() ) {
881 displayName = KMime::decodeRFC2047String(displayName).utf8();
882 comment = KMime::decodeRFC2047String(comment).utf8();
884 normalizedAddressList <<
886 decodeIDN( TQString::fromUtf8( addrSpec ) ),
887 TQString::fromUtf8( comment ) );
890 kdDebug() <<
"splitting address failed: " << *it << endl;
899 return normalizedAddressList.join(
", " );
911 TQStringList normalizedAddressList;
913 TQCString displayName, addrSpec, comment;
915 for( TQStringList::ConstIterator it = addressList.begin();
916 ( it != addressList.end() );
918 if( !(*it).isEmpty() ) {
922 normalizedAddressList <<
924 encodeIDN( TQString::fromUtf8( addrSpec ) ),
925 TQString::fromUtf8( comment ) );
928 kdDebug() <<
"splitting address failed: " << *it << endl;
938 return normalizedAddressList.join(
", " );
944 static TQString escapeQuotes(
const TQString & str )
951 escaped.reserve( 2*str.length() );
952 unsigned int len = 0;
953 for (
unsigned int i = 0; i < str.length(); ++i, ++len ) {
954 if ( str[i] ==
'"' ) {
958 else if ( str[i] ==
'\\' ) {
962 if ( i >= str.length() )
965 escaped[len] = str[i];
967 escaped.truncate( len );
974 TQString quoted = str;
976 TQRegExp needQuotes(
"[^ 0-9A-Za-z\\x0080-\\xFFFF]" );
978 if ( ( quoted[0] ==
'"' ) && ( quoted[quoted.length() - 1] ==
'"' ) ) {
979 quoted =
"\"" + escapeQuotes( quoted.mid( 1, quoted.length() - 2 ) ) +
"\"";
981 else if ( quoted.find( needQuotes ) != -1 ) {
982 quoted =
"\"" + escapeQuotes( quoted ) +
"\"";
TDE_EXPORT TQString simpleEmailAddressErrorMsg()
Returns a i18n string to be used in msgboxes this allows for error messages to be the same across the...
TDE_EXPORT bool getNameAndMail(const TQString &aStr, TQString &name, TQString &mail)
Return email address and name from string.
TDE_EXPORT TQString normalizeAddressesAndEncodeIDNs(const TQString &str)
Normalizes all email addresses in the given list and encodes all IDNs in punycode.
TDE_EXPORT bool compareEmail(const TQString &email1, const TQString &email2, bool matchName)
Compare two email addresses.
TDE_EXPORT TQStringList splitEmailAddrList(const TQString &aStr)
Split a comma separated list of email addresses.
TDE_EXPORT TQCString getEmailAddress(const TQCString &address)
Returns the pure email address (addr-spec in RFC2822) of the given address (mailbox in RFC2822).
TDE_EXPORT EmailParseResult splitAddress(const TQCString &address, TQCString &displayName, TQCString &addrSpec, TQCString &comment)
Splits the given address into display name, email address and comment.
TDE_EXPORT TQString decodeIDN(const TQString &addrSpec)
Decodes the punycode domain part of the given addr-spec if it's an IDN.
TDE_EXPORT TQString quoteNameIfNecessary(const TQString &str)
Add quote characters around the given string if it contains a character that makes that necessary,...
TDE_EXPORT TQString normalizeAddressesAndDecodeIDNs(const TQString &addresses)
Normalizes all email addresses in the given list and decodes all IDNs.
TDE_EXPORT TQString encodeIDN(const TQString &addrSpec)
Encodes the domain part of the given addr-spec in punycode if it's an IDN.
TDE_EXPORT TQString emailParseResultToString(EmailParseResult errorCode)
Translate the enum errorcodes from emailParseResult into i18n'd strings that can be used for msg boxe...
TDE_EXPORT bool isValidSimpleEmailAddress(const TQString &aStr)
Validates an email address in the form of joe@example.org.
TDE_EXPORT TQCString getFirstEmailAddress(const TQCString &addresses)
Returns the pure email address (addr-spec in RFC2822) of the first email address of a list of address...
EmailParseResult
Result type for splitAddress, isValidEmailAddress.
TDE_EXPORT TQString normalizedAddress(const TQString &displayName, const TQString &addrSpec, const TQString &comment)
Returns a normalized address built from the given parts.
TDE_EXPORT EmailParseResult isValidEmailAddress(const TQString &aStr)
Validates an email address in the form of "Joe User" joe@example.org.