00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "email.h"
00022
00023 #include <kdebug.h>
00024 #include <klocale.h>
00025 #include <kidna.h>
00026
00027 #include <qregexp.h>
00028
00029
00030 QStringList KPIM::splitEmailAddrList(const QString& aStr)
00031 {
00032
00033
00034
00035
00036
00037
00038
00039
00040 QStringList list;
00041
00042 if (aStr.isEmpty())
00043 return list;
00044
00045 QString addr;
00046 uint addrstart = 0;
00047 int commentlevel = 0;
00048 bool insidequote = false;
00049
00050 for (uint index=0; index<aStr.length(); index++) {
00051
00052
00053 switch (aStr[index].latin1()) {
00054 case '"' :
00055 if (commentlevel == 0)
00056 insidequote = !insidequote;
00057 break;
00058 case '(' :
00059 if (!insidequote)
00060 commentlevel++;
00061 break;
00062 case ')' :
00063 if (!insidequote) {
00064 if (commentlevel > 0)
00065 commentlevel--;
00066 else {
00067 kdDebug(5300) << "Error in address splitting: Unmatched ')'"
00068 << endl;
00069 return list;
00070 }
00071 }
00072 break;
00073 case '\\' :
00074 index++;
00075 break;
00076 case ',' :
00077 case ';' :
00078 if (!insidequote && (commentlevel == 0)) {
00079 addr = aStr.mid(addrstart, index-addrstart);
00080 if (!addr.isEmpty())
00081 list += addr.simplifyWhiteSpace();
00082 addrstart = index+1;
00083 }
00084 break;
00085 }
00086 }
00087
00088 if (!insidequote && (commentlevel == 0)) {
00089 addr = aStr.mid(addrstart, aStr.length()-addrstart);
00090 if (!addr.isEmpty())
00091 list += addr.simplifyWhiteSpace();
00092 }
00093 else
00094 kdDebug(5300) << "Error in address splitting: "
00095 << "Unexpected end of address list"
00096 << endl;
00097
00098 return list;
00099 }
00100
00101
00102
00103 KPIM::EmailParseResult splitAddressInternal( const QCString& address,
00104 QCString & displayName,
00105 QCString & addrSpec,
00106 QCString & comment,
00107 bool allowMultipleAddresses )
00108 {
00109
00110
00111 displayName = "";
00112 addrSpec = "";
00113 comment = "";
00114
00115 if ( address.isEmpty() )
00116 return KPIM::AddressEmpty;
00117
00118
00119
00120
00121
00122 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
00123 bool inQuotedString = false;
00124 int commentLevel = 0;
00125 bool stop = false;
00126
00127 for ( char* p = address.data(); *p && !stop; ++p ) {
00128 switch ( context ) {
00129 case TopLevel : {
00130 switch ( *p ) {
00131 case '"' : inQuotedString = !inQuotedString;
00132 displayName += *p;
00133 break;
00134 case '(' : if ( !inQuotedString ) {
00135 context = InComment;
00136 commentLevel = 1;
00137 }
00138 else
00139 displayName += *p;
00140 break;
00141 case '<' : if ( !inQuotedString ) {
00142 context = InAngleAddress;
00143 }
00144 else
00145 displayName += *p;
00146 break;
00147 case '\\' :
00148 displayName += *p;
00149 ++p;
00150 if ( *p )
00151 displayName += *p;
00152 else
00153 return KPIM::UnexpectedEnd;
00154 break;
00155 case ',' :
00156 case ';' : if ( !inQuotedString ) {
00157 if ( allowMultipleAddresses )
00158 stop = true;
00159 else
00160 return KPIM::UnexpectedComma;
00161 }
00162 else
00163 displayName += *p;
00164 break;
00165 default : displayName += *p;
00166 }
00167 break;
00168 }
00169 case InComment : {
00170 switch ( *p ) {
00171 case '(' : ++commentLevel;
00172 comment += *p;
00173 break;
00174 case ')' : --commentLevel;
00175 if ( commentLevel == 0 ) {
00176 context = TopLevel;
00177 comment += ' ';
00178 }
00179 else
00180 comment += *p;
00181 break;
00182 case '\\' :
00183 comment += *p;
00184 ++p;
00185 if ( *p )
00186 comment += *p;
00187 else
00188 return KPIM::UnexpectedEnd;
00189 break;
00190 default : comment += *p;
00191 }
00192 break;
00193 }
00194 case InAngleAddress : {
00195 switch ( *p ) {
00196 case '"' : inQuotedString = !inQuotedString;
00197 addrSpec += *p;
00198 break;
00199 case '>' : if ( !inQuotedString ) {
00200 context = TopLevel;
00201 }
00202 else
00203 addrSpec += *p;
00204 break;
00205 case '\\' :
00206 addrSpec += *p;
00207 ++p;
00208 if ( *p )
00209 addrSpec += *p;
00210 else
00211 return KPIM::UnexpectedEnd;
00212 break;
00213 default : addrSpec += *p;
00214 }
00215 break;
00216 }
00217 }
00218 }
00219
00220 if ( inQuotedString )
00221 return KPIM::UnbalancedQuote;
00222 if ( context == InComment )
00223 return KPIM::UnbalancedParens;
00224 if ( context == InAngleAddress )
00225 return KPIM::UnclosedAngleAddr;
00226
00227 displayName = displayName.stripWhiteSpace();
00228 comment = comment.stripWhiteSpace();
00229 addrSpec = addrSpec.stripWhiteSpace();
00230
00231 if ( addrSpec.isEmpty() ) {
00232 if ( displayName.isEmpty() )
00233 return KPIM::NoAddressSpec;
00234 else {
00235 addrSpec = displayName;
00236 displayName.truncate( 0 );
00237 }
00238 }
00239
00240
00241
00242
00243
00244 return KPIM::AddressOk;
00245 }
00246
00247
00248
00249 KPIM::EmailParseResult KPIM::splitAddress( const QCString& address,
00250 QCString & displayName,
00251 QCString & addrSpec,
00252 QCString & comment )
00253 {
00254 return splitAddressInternal( address, displayName, addrSpec, comment,
00255 false );
00256 }
00257
00258
00259
00260 KPIM::EmailParseResult KPIM::splitAddress( const QString & address,
00261 QString & displayName,
00262 QString & addrSpec,
00263 QString & comment )
00264 {
00265 QCString d, a, c;
00266 KPIM::EmailParseResult result = splitAddress( address.utf8(), d, a, c );
00267 if ( result == AddressOk ) {
00268 displayName = QString::fromUtf8( d );
00269 addrSpec = QString::fromUtf8( a );
00270 comment = QString::fromUtf8( c );
00271 }
00272 return result;
00273 }
00274
00275
00276
00277 KPIM::EmailParseResult KPIM::isValidEmailAddress( const QString& aStr )
00278 {
00279
00280
00281 if ( aStr.isEmpty() ) {
00282 return AddressEmpty;
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292 bool tooManyAtsFlag = false;
00293
00294 int atCount = aStr.contains('@');
00295 if ( atCount > 1 ) {
00296 tooManyAtsFlag = true;;
00297 } else if ( atCount == 0 ) {
00298 return TooFewAts;
00299 }
00300
00301
00302
00303
00304 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
00305 bool inQuotedString = false;
00306 int commentLevel = 0;
00307
00308 unsigned int strlen = aStr.length();
00309
00310 for ( unsigned int index=0; index < strlen; index++ ) {
00311 switch ( context ) {
00312 case TopLevel : {
00313 switch ( aStr[index].latin1() ) {
00314 case '"' : inQuotedString = !inQuotedString;
00315 break;
00316 case '(' :
00317 if ( !inQuotedString ) {
00318 context = InComment;
00319 commentLevel = 1;
00320 }
00321 break;
00322 case '[' :
00323 if ( !inQuotedString ) {
00324 return InvalidDisplayName;
00325 }
00326 break;
00327 case ']' :
00328 if ( !inQuotedString ) {
00329 return InvalidDisplayName;
00330 }
00331 break;
00332 case ':' :
00333 if ( !inQuotedString ) {
00334 return DisallowedChar;
00335 }
00336 break;
00337 case '<' :
00338 if ( !inQuotedString ) {
00339 context = InAngleAddress;
00340 }
00341 break;
00342 case '\\' :
00343 ++index;
00344 if (( index + 1 )> strlen ) {
00345 return UnexpectedEnd;
00346 }
00347 break;
00348 case ',' :
00349 case ';' :
00350 if ( !inQuotedString )
00351 return UnexpectedComma;
00352 break;
00353 case ')' :
00354 if ( !inQuotedString )
00355 return UnbalancedParens;
00356 break;
00357 case '>' :
00358 if ( !inQuotedString )
00359 return UnopenedAngleAddr;
00360 break;
00361 case '@' :
00362 if ( !inQuotedString ) {
00363 if ( index == 0 ) {
00364 return MissingLocalPart;
00365 } else if( index == strlen-1 ) {
00366 return MissingDomainPart;
00367 }
00368 } else if ( inQuotedString ) {
00369 --atCount;
00370 if ( atCount == 1 ) {
00371 tooManyAtsFlag = false;
00372 }
00373 }
00374 break;
00375 }
00376 break;
00377 }
00378 case InComment : {
00379 switch ( aStr[index] ) {
00380 case '(' : ++commentLevel;
00381 break;
00382 case ')' : --commentLevel;
00383 if ( commentLevel == 0 ) {
00384 context = TopLevel;
00385 }
00386 break;
00387 case '\\' :
00388 ++index;
00389 if (( index + 1 )> strlen ) {
00390 return UnexpectedEnd;
00391 }
00392 break;
00393 }
00394 break;
00395 }
00396
00397 case InAngleAddress : {
00398 switch ( aStr[index] ) {
00399 case ',' :
00400 case ';' :
00401 if ( !inQuotedString ) {
00402 return UnexpectedComma;
00403 }
00404 break;
00405 case '"' : inQuotedString = !inQuotedString;
00406 break;
00407 case '@' :
00408 if ( inQuotedString ) {
00409 --atCount;
00410 if ( atCount == 1 ) {
00411 tooManyAtsFlag = false;
00412 }
00413 }
00414 break;
00415 case '>' :
00416 if ( !inQuotedString ) {
00417 context = TopLevel;
00418 break;
00419 }
00420 break;
00421 case '\\' :
00422 ++index;
00423 if (( index + 1 )> strlen ) {
00424 return UnexpectedEnd;
00425 }
00426 break;
00427 }
00428 break;
00429 }
00430 }
00431 }
00432
00433 if ( atCount == 0 && !inQuotedString )
00434 return TooFewAts;
00435
00436 if ( inQuotedString )
00437 return UnbalancedQuote;
00438
00439 if ( context == InComment )
00440 return UnbalancedParens;
00441
00442 if ( context == InAngleAddress )
00443 return UnclosedAngleAddr;
00444
00445 if ( tooManyAtsFlag ) {
00446 return TooManyAts;
00447 }
00448 return AddressOk;
00449 }
00450
00451
00452 QString KPIM::emailParseResultToString( EmailParseResult errorCode )
00453 {
00454 switch ( errorCode ) {
00455 case TooManyAts :
00456 return i18n("The email address you entered is not valid because it "
00457 "contains more than one @. "
00458 "You will not create valid messages if you do not "
00459 "change your address.");
00460 case TooFewAts :
00461 return i18n("The email address you entered is not valid because it "
00462 "does not contain a @."
00463 "You will not create valid messages if you do not "
00464 "change your address.");
00465 case AddressEmpty :
00466 return i18n("You have to enter something in the email address field.");
00467 case MissingLocalPart :
00468 return i18n("The email address you entered is not valid because it "
00469 "does not contain a local part.");
00470 case MissingDomainPart :
00471 return i18n("The email address you entered is not valid because it "
00472 "does not contain a domain part.");
00473 case UnbalancedParens :
00474 return i18n("The email address you entered is not valid because it "
00475 "contains unclosed comments/brackets.");
00476 case AddressOk :
00477 return i18n("The email address you entered is valid.");
00478 case UnclosedAngleAddr :
00479 return i18n("The email address you entered is not valid because it "
00480 "contains an unclosed anglebracket.");
00481 case UnopenedAngleAddr :
00482 return i18n("The email address you entered is not valid because it "
00483 "contains an unopened anglebracket.");
00484 case UnexpectedComma :
00485 return i18n("The email address you have entered is not valid because it "
00486 "contains an unexpected comma.");
00487 case UnexpectedEnd :
00488 return i18n("The email address you entered is not valid because it ended "
00489 "unexpectedly, this probably means you have used an escaping type "
00490 "character like an \\ as the last character in your email "
00491 "address.");
00492 case UnbalancedQuote :
00493 return i18n("The email address you entered is not valid because it "
00494 "contains quoted text which does not end.");
00495 case NoAddressSpec :
00496 return i18n("The email address you entered is not valid because it "
00497 "does not seem to contain an actual email address, i.e. "
00498 "something of the form joe@kde.org.");
00499 case DisallowedChar :
00500 return i18n("The email address you entered is not valid because it "
00501 "contains an illegal character.");
00502 case InvalidDisplayName :
00503 return i18n("The email address you have entered is not valid because it "
00504 "contains an invalid displayname.");
00505 }
00506 return i18n("Unknown problem with email address");
00507 }
00508
00509
00510 bool KPIM::isValidSimpleEmailAddress( const QString& aStr )
00511 {
00512
00513
00514 if ( aStr.isEmpty() ) {
00515 return false;
00516 }
00517
00518 int atChar = aStr.findRev( '@' );
00519 QString domainPart = aStr.mid( atChar + 1);
00520 QString localPart = aStr.left( atChar );
00521 bool tooManyAtsFlag = false;
00522 bool inQuotedString = false;
00523 int atCount = localPart.contains( '@' );
00524
00525 unsigned int strlen = localPart.length();
00526 for ( unsigned int index=0; index < strlen; index++ ) {
00527 switch( localPart[ index ].latin1() ) {
00528 case '"' : inQuotedString = !inQuotedString;
00529 break;
00530 case '@' :
00531 if ( inQuotedString ) {
00532 --atCount;
00533 if ( atCount == 0 ) {
00534 tooManyAtsFlag = false;
00535 }
00536 }
00537 break;
00538 }
00539 }
00540
00541 QString addrRx = "[a-zA-Z]*[~|{}`\\^?=/+*'&%$#!_\\w.-]*[~|{}`\\^?=/+*'&%$#!_a-zA-Z0-9-]@";
00542 if ( localPart[ 0 ] == '\"' || localPart[ localPart.length()-1 ] == '\"' ) {
00543 addrRx = "\"[a-zA-Z@]*[\\w.@-]*[a-zA-Z0-9@]\"@";
00544 }
00545 if ( domainPart[ 0 ] == '[' || domainPart[ domainPart.length()-1 ] == ']' ) {
00546 addrRx += "\\[[0-9]{,3}(\\.[0-9]{,3}){3}\\]";
00547 } else {
00548 addrRx += "[\\w-]+(\\.[\\w-]+)*";
00549 }
00550 QRegExp rx( addrRx );
00551 return rx.exactMatch( aStr ) && !tooManyAtsFlag;
00552 }
00553
00554
00555 QString KPIM::simpleEmailAddressErrorMsg()
00556 {
00557 return i18n("The email address you entered is not valid because it "
00558 "does not seem to contain an actual email address, i.e. "
00559 "something of the form joe@kde.org.");
00560 }
00561
00562 QCString KPIM::getEmailAddress( const QCString & address )
00563 {
00564 QCString dummy1, dummy2, addrSpec;
00565 KPIM::EmailParseResult result =
00566 splitAddressInternal( address, dummy1, addrSpec, dummy2,
00567 false );
00568 if ( result != AddressOk ) {
00569 addrSpec = QCString();
00570 kdDebug()
00571 << "Input: aStr\nError:"
00572 << emailParseResultToString( result ) << endl;
00573 }
00574
00575 return addrSpec;
00576 }
00577
00578
00579
00580 QString KPIM::getEmailAddress( const QString & address )
00581 {
00582 return QString::fromUtf8( getEmailAddress( address.utf8() ) );
00583 }
00584
00585
00586
00587 QCString KPIM::getFirstEmailAddress( const QCString & addresses )
00588 {
00589 QCString dummy1, dummy2, addrSpec;
00590 KPIM::EmailParseResult result =
00591 splitAddressInternal( addresses, dummy1, addrSpec, dummy2,
00592 true );
00593 if ( result != AddressOk ) {
00594 addrSpec = QCString();
00595 kdDebug()
00596 << "Input: aStr\nError:"
00597 << emailParseResultToString( result ) << endl;
00598 }
00599
00600 return addrSpec;
00601 }
00602
00603
00604
00605 QString KPIM::getFirstEmailAddress( const QString & addresses )
00606 {
00607 return QString::fromUtf8( getFirstEmailAddress( addresses.utf8() ) );
00608 }
00609
00610
00611
00612 bool KPIM::getNameAndMail(const QString& aStr, QString& name, QString& mail)
00613 {
00614 name = QString::null;
00615 mail = QString::null;
00616
00617 const int len=aStr.length();
00618 const char cQuotes = '"';
00619
00620 bool bInComment = false;
00621 bool bInQuotesOutsideOfEmail = false;
00622 int i=0, iAd=0, iMailStart=0, iMailEnd=0;
00623 QChar c;
00624 unsigned int commentstack = 0;
00625
00626
00627
00628 while( i < len ){
00629 c = aStr[i];
00630 if( '(' == c ) commentstack++;
00631 if( ')' == c ) commentstack--;
00632 bInComment = commentstack != 0;
00633 if( '"' == c && !bInComment )
00634 bInQuotesOutsideOfEmail = !bInQuotesOutsideOfEmail;
00635
00636 if( !bInComment && !bInQuotesOutsideOfEmail ){
00637 if( '@' == c ){
00638 iAd = i;
00639 break;
00640 }
00641 }
00642 ++i;
00643 }
00644
00645 if ( !iAd ) {
00646
00647
00648
00649 for( i = 0; len > i; ++i ) {
00650 c = aStr[i];
00651 if( '<' != c )
00652 name.append( c );
00653 else
00654 break;
00655 }
00656 mail = aStr.mid( i+1 );
00657 if ( mail.endsWith( ">" ) )
00658 mail.truncate( mail.length() - 1 );
00659
00660 } else {
00661
00662
00663
00664 bInComment = false;
00665 bInQuotesOutsideOfEmail = false;
00666 for( i = iAd-1; 0 <= i; --i ) {
00667 c = aStr[i];
00668 if( bInComment ) {
00669 if( '(' == c ) {
00670 if( !name.isEmpty() )
00671 name.prepend( ' ' );
00672 bInComment = false;
00673 } else {
00674 name.prepend( c );
00675 }
00676 }else if( bInQuotesOutsideOfEmail ){
00677 if( cQuotes == c )
00678 bInQuotesOutsideOfEmail = false;
00679 else
00680 name.prepend( c );
00681 }else{
00682
00683 if( ',' == c )
00684 break;
00685
00686 if( iMailStart ){
00687 if( cQuotes == c )
00688 bInQuotesOutsideOfEmail = true;
00689 else
00690 name.prepend( c );
00691 }else{
00692 switch( c ){
00693 case '<':
00694 iMailStart = i;
00695 break;
00696 case ')':
00697 if( !name.isEmpty() )
00698 name.prepend( ' ' );
00699 bInComment = true;
00700 break;
00701 default:
00702 if( ' ' != c )
00703 mail.prepend( c );
00704 }
00705 }
00706 }
00707 }
00708
00709 name = name.simplifyWhiteSpace();
00710 mail = mail.simplifyWhiteSpace();
00711
00712 if( mail.isEmpty() )
00713 return false;
00714
00715 mail.append('@');
00716
00717
00718
00719
00720 bInComment = false;
00721 bInQuotesOutsideOfEmail = false;
00722 int parenthesesNesting = 0;
00723 for( i = iAd+1; len > i; ++i ) {
00724 c = aStr[i];
00725 if( bInComment ){
00726 if( ')' == c ){
00727 if ( --parenthesesNesting == 0 ) {
00728 bInComment = false;
00729 if( !name.isEmpty() )
00730 name.append( ' ' );
00731 } else {
00732
00733 name.append( ')' );
00734 }
00735 } else {
00736 if( '(' == c ) {
00737
00738 ++parenthesesNesting;
00739 }
00740 name.append( c );
00741 }
00742 }else if( bInQuotesOutsideOfEmail ){
00743 if( cQuotes == c )
00744 bInQuotesOutsideOfEmail = false;
00745 else
00746 name.append( c );
00747 }else{
00748
00749 if( ',' == c )
00750 break;
00751
00752 if( iMailEnd ){
00753 if( cQuotes == c )
00754 bInQuotesOutsideOfEmail = true;
00755 else
00756 name.append( c );
00757 }else{
00758 switch( c ){
00759 case '>':
00760 iMailEnd = i;
00761 break;
00762 case '(':
00763 if( !name.isEmpty() )
00764 name.append( ' ' );
00765 if ( ++parenthesesNesting > 0 )
00766 bInComment = true;
00767 break;
00768 default:
00769 if( ' ' != c )
00770 mail.append( c );
00771 }
00772 }
00773 }
00774 }
00775 }
00776
00777 name = name.simplifyWhiteSpace();
00778 mail = mail.simplifyWhiteSpace();
00779
00780 return ! (name.isEmpty() || mail.isEmpty());
00781 }
00782
00783
00784
00785 bool KPIM::compareEmail( const QString& email1, const QString& email2,
00786 bool matchName )
00787 {
00788 QString e1Name, e1Email, e2Name, e2Email;
00789
00790 getNameAndMail( email1, e1Name, e1Email );
00791 getNameAndMail( email2, e2Name, e2Email );
00792
00793 return e1Email == e2Email &&
00794 ( !matchName || ( e1Name == e2Name ) );
00795 }
00796
00797
00798
00799 QString KPIM::normalizedAddress( const QString & displayName,
00800 const QString & addrSpec,
00801 const QString & comment )
00802 {
00803 if ( displayName.isEmpty() && comment.isEmpty() )
00804 return addrSpec;
00805 else if ( comment.isEmpty() )
00806 return displayName + " <" + addrSpec + ">";
00807 else if ( displayName.isEmpty() ) {
00808 QString commentStr = comment;
00809 return quoteNameIfNecessary( commentStr ) + " <" + addrSpec + ">";
00810 }
00811 else
00812 return displayName + " (" + comment + ") <" + addrSpec + ">";
00813 }
00814
00815
00816
00817 QString KPIM::decodeIDN( const QString & addrSpec )
00818 {
00819 const int atPos = addrSpec.findRev( '@' );
00820 if ( atPos == -1 )
00821 return addrSpec;
00822
00823 QString idn = KIDNA::toUnicode( addrSpec.mid( atPos + 1 ) );
00824 if ( idn.isEmpty() )
00825 return QString::null;
00826
00827 return addrSpec.left( atPos + 1 ) + idn;
00828 }
00829
00830
00831
00832 QString KPIM::encodeIDN( const QString & addrSpec )
00833 {
00834 const int atPos = addrSpec.findRev( '@' );
00835 if ( atPos == -1 )
00836 return addrSpec;
00837
00838 QString idn = KIDNA::toAscii( addrSpec.mid( atPos + 1 ) );
00839 if ( idn.isEmpty() )
00840 return addrSpec;
00841
00842 return addrSpec.left( atPos + 1 ) + idn;
00843 }
00844
00845
00846
00847 QString KPIM::normalizeAddressesAndDecodeIDNs( const QString & str )
00848 {
00849
00850
00851 if( str.isEmpty() )
00852 return str;
00853
00854 const QStringList addressList = KPIM::splitEmailAddrList( str );
00855 QStringList normalizedAddressList;
00856
00857 QCString displayName, addrSpec, comment;
00858
00859 for( QStringList::ConstIterator it = addressList.begin();
00860 ( it != addressList.end() );
00861 ++it ) {
00862 if( !(*it).isEmpty() ) {
00863 if ( KPIM::splitAddress( (*it).utf8(), displayName, addrSpec, comment )
00864 == AddressOk ) {
00865
00866 normalizedAddressList <<
00867 normalizedAddress( QString::fromUtf8( displayName ),
00868 decodeIDN( QString::fromUtf8( addrSpec ) ),
00869 QString::fromUtf8( comment ) );
00870 }
00871 else {
00872 kdDebug() << "splitting address failed: " << *it << endl;
00873 }
00874 }
00875 }
00876
00877
00878
00879
00880
00881 return normalizedAddressList.join( ", " );
00882 }
00883
00884
00885 QString KPIM::normalizeAddressesAndEncodeIDNs( const QString & str )
00886 {
00887
00888
00889 if( str.isEmpty() )
00890 return str;
00891
00892 const QStringList addressList = KPIM::splitEmailAddrList( str );
00893 QStringList normalizedAddressList;
00894
00895 QCString displayName, addrSpec, comment;
00896
00897 for( QStringList::ConstIterator it = addressList.begin();
00898 ( it != addressList.end() );
00899 ++it ) {
00900 if( !(*it).isEmpty() ) {
00901 if ( KPIM::splitAddress( (*it).utf8(), displayName, addrSpec, comment )
00902 == AddressOk ) {
00903
00904 normalizedAddressList <<
00905 normalizedAddress( QString::fromUtf8( displayName ),
00906 encodeIDN( QString::fromUtf8( addrSpec ) ),
00907 QString::fromUtf8( comment ) );
00908 }
00909 else {
00910 kdDebug() << "splitting address failed: " << *it << endl;
00911 }
00912 }
00913 }
00914
00915
00916
00917
00918
00919
00920 return normalizedAddressList.join( ", " );
00921 }
00922
00923
00924
00925
00926 static QString escapeQuotes( const QString & str )
00927 {
00928 if ( str.isEmpty() )
00929 return QString();
00930
00931 QString escaped;
00932
00933 escaped.reserve( 2*str.length() );
00934 unsigned int len = 0;
00935 for ( unsigned int i = 0; i < str.length(); ++i, ++len ) {
00936 if ( str[i] == '"' ) {
00937 escaped[len] = '\\';
00938 ++len;
00939 }
00940 else if ( str[i] == '\\' ) {
00941 escaped[len] = '\\';
00942 ++len;
00943 ++i;
00944 if ( i >= str.length() )
00945 break;
00946 }
00947 escaped[len] = str[i];
00948 }
00949 escaped.truncate( len );
00950 return escaped;
00951 }
00952
00953
00954 QString KPIM::quoteNameIfNecessary( const QString &str )
00955 {
00956 QString quoted = str;
00957
00958 QRegExp needQuotes( "[^ 0-9A-Za-z\\x0080-\\xFFFF]" );
00959
00960 if ( ( quoted[0] == '"' ) && ( quoted[quoted.length() - 1] == '"' ) ) {
00961 quoted = "\"" + escapeQuotes( quoted.mid( 1, quoted.length() - 2 ) ) + "\"";
00962 }
00963 else if ( quoted.find( needQuotes ) != -1 ) {
00964 quoted = "\"" + escapeQuotes( quoted ) + "\"";
00965 }
00966
00967 return quoted;
00968 }
00969