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