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( ", " );
944static 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 ) + "\"";
KDE_EXPORT TQString normalizeAddressesAndEncodeIDNs(const TQString &str) Normalizes all email addresses in the given list and encodes all IDNs in punycode.
KDE_EXPORT TQString encodeIDN(const TQString &addrSpec) Encodes the domain part of the given addr-spec in punycode if it's an IDN.
KDE_EXPORT TQString simpleEmailAddressErrorMsg() Returns a i18n string to be used in msgboxes this allows for error messages to be the same across the...
KDE_EXPORT TQString quoteNameIfNecessary(const TQString &str) Add quote characters around the given string if it contains a character that makes that necessary,...
KDE_EXPORT TQStringList splitEmailAddrList(const TQString &aStr) Split a comma separated list of email addresses.
KDE_EXPORT bool compareEmail(const TQString &email1, const TQString &email2, bool matchName) Compare two email addresses.
KDE_EXPORT EmailParseResult splitAddress(const TQCString &address, TQCString &displayName, TQCString &addrSpec, TQCString &comment) Splits the given address into display name, email address and comment.
KDE_EXPORT TQString normalizeAddressesAndDecodeIDNs(const TQString &addresses) Normalizes all email addresses in the given list and decodes all IDNs.
KDE_EXPORT TQString decodeIDN(const TQString &addrSpec) Decodes the punycode domain part of the given addr-spec if it's an IDN.
KDE_EXPORT bool getNameAndMail(const TQString &aStr, TQString &name, TQString &mail) Return email address and name from string.
KDE_EXPORT TQString normalizedAddress(const TQString &displayName, const TQString &addrSpec, const TQString &comment) Returns a normalized address built from the given parts.
KDE_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...
KDE_EXPORT TQString emailParseResultToString(EmailParseResult errorCode) Translate the enum errorcodes from emailParseResult into i18n'd strings that can be used for msg boxe...
KDE_EXPORT TQCString getEmailAddress(const TQCString &address) Returns the pure email address (addr-spec in RFC2822) of the given address (mailbox in RFC2822).
KDE_EXPORT bool isValidSimpleEmailAddress(const TQString &aStr) Validates an email address in the form of joe@example.org.
EmailParseResult Result type for splitAddress, isValidEmailAddress.
KDE_EXPORT EmailParseResult isValidEmailAddress(const TQString &aStr) Validates an email address in the form of "Joe User" joe@example.org.
|