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 QString realDisplayName = displayName;
00813 realDisplayName.remove( QChar( 0x202D ) );
00814 realDisplayName.remove( QChar( 0x202E ) );
00815 realDisplayName.remove( QChar( 0x202A ) );
00816 realDisplayName.remove( QChar( 0x202B ) );
00817
00818 if ( realDisplayName.isEmpty() && comment.isEmpty() )
00819 return addrSpec;
00820 else if ( comment.isEmpty() )
00821 return quoteNameIfNecessary( realDisplayName ) + " <" + addrSpec + ">";
00822 else if ( realDisplayName.isEmpty() ) {
00823 QString commentStr = comment;
00824 return quoteNameIfNecessary( commentStr ) + " <" + addrSpec + ">";
00825 }
00826 else
00827 return realDisplayName + " (" + comment + ") <" + addrSpec + ">";
00828 }
00829
00830
00831
00832 QString KPIM::decodeIDN( const QString & addrSpec )
00833 {
00834 const int atPos = addrSpec.findRev( '@' );
00835 if ( atPos == -1 )
00836 return addrSpec;
00837
00838 QString idn = KIDNA::toUnicode( addrSpec.mid( atPos + 1 ) );
00839 if ( idn.isEmpty() )
00840 return QString::null;
00841
00842 return addrSpec.left( atPos + 1 ) + idn;
00843 }
00844
00845
00846
00847 QString KPIM::encodeIDN( const QString & addrSpec )
00848 {
00849 const int atPos = addrSpec.findRev( '@' );
00850 if ( atPos == -1 )
00851 return addrSpec;
00852
00853 QString idn = KIDNA::toAscii( addrSpec.mid( atPos + 1 ) );
00854 if ( idn.isEmpty() )
00855 return addrSpec;
00856
00857 return addrSpec.left( atPos + 1 ) + idn;
00858 }
00859
00860
00861
00862 QString KPIM::normalizeAddressesAndDecodeIDNs( const QString & str )
00863 {
00864
00865
00866 if( str.isEmpty() )
00867 return str;
00868
00869 const QStringList addressList = KPIM::splitEmailAddrList( str );
00870 QStringList normalizedAddressList;
00871
00872 QCString displayName, addrSpec, comment;
00873
00874 for( QStringList::ConstIterator it = addressList.begin();
00875 ( it != addressList.end() );
00876 ++it ) {
00877 if( !(*it).isEmpty() ) {
00878 if ( KPIM::splitAddress( (*it).utf8(), displayName, addrSpec, comment )
00879 == AddressOk ) {
00880
00881 displayName = KMime::decodeRFC2047String(displayName).utf8();
00882 comment = KMime::decodeRFC2047String(comment).utf8();
00883
00884 normalizedAddressList <<
00885 normalizedAddress( QString::fromUtf8( displayName ),
00886 decodeIDN( QString::fromUtf8( addrSpec ) ),
00887 QString::fromUtf8( comment ) );
00888 }
00889 else {
00890 kdDebug() << "splitting address failed: " << *it << endl;
00891 }
00892 }
00893 }
00894
00895
00896
00897
00898
00899 return normalizedAddressList.join( ", " );
00900 }
00901
00902
00903 QString KPIM::normalizeAddressesAndEncodeIDNs( const QString & str )
00904 {
00905
00906
00907 if( str.isEmpty() )
00908 return str;
00909
00910 const QStringList addressList = KPIM::splitEmailAddrList( str );
00911 QStringList normalizedAddressList;
00912
00913 QCString displayName, addrSpec, comment;
00914
00915 for( QStringList::ConstIterator it = addressList.begin();
00916 ( it != addressList.end() );
00917 ++it ) {
00918 if( !(*it).isEmpty() ) {
00919 if ( KPIM::splitAddress( (*it).utf8(), displayName, addrSpec, comment )
00920 == AddressOk ) {
00921
00922 normalizedAddressList <<
00923 normalizedAddress( QString::fromUtf8( displayName ),
00924 encodeIDN( QString::fromUtf8( addrSpec ) ),
00925 QString::fromUtf8( comment ) );
00926 }
00927 else {
00928 kdDebug() << "splitting address failed: " << *it << endl;
00929 }
00930 }
00931 }
00932
00933
00934
00935
00936
00937
00938 return normalizedAddressList.join( ", " );
00939 }
00940
00941
00942
00943
00944 static QString escapeQuotes( const QString & str )
00945 {
00946 if ( str.isEmpty() )
00947 return QString();
00948
00949 QString escaped;
00950
00951 escaped.reserve( 2*str.length() );
00952 unsigned int len = 0;
00953 for ( unsigned int i = 0; i < str.length(); ++i, ++len ) {
00954 if ( str[i] == '"' ) {
00955 escaped[len] = '\\';
00956 ++len;
00957 }
00958 else if ( str[i] == '\\' ) {
00959 escaped[len] = '\\';
00960 ++len;
00961 ++i;
00962 if ( i >= str.length() )
00963 break;
00964 }
00965 escaped[len] = str[i];
00966 }
00967 escaped.truncate( len );
00968 return escaped;
00969 }
00970
00971
00972 QString KPIM::quoteNameIfNecessary( const QString &str )
00973 {
00974 QString quoted = str;
00975
00976 QRegExp needQuotes( "[^ 0-9A-Za-z\\x0080-\\xFFFF]" );
00977
00978 if ( ( quoted[0] == '"' ) && ( quoted[quoted.length() - 1] == '"' ) ) {
00979 quoted = "\"" + escapeQuotes( quoted.mid( 1, quoted.length() - 2 ) ) + "\"";
00980 }
00981 else if ( quoted.find( needQuotes ) != -1 ) {
00982 quoted = "\"" + escapeQuotes( quoted ) + "\"";
00983 }
00984
00985 return quoted;
00986 }
00987