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