libkdepim Library API Documentation

email.cpp

00001 /*  -*- mode: C++; c-file-style: "gnu" -*-
00002 
00003     This file is part of kdepim.
00004     Copyright (c) 2004 KDEPIM developers
00005 
00006     KMail is free software; you can redistribute it and/or modify it
00007     under the terms of the GNU General Public License, version 2, as
00008     published by the Free Software Foundation.
00009 
00010     KMail is distributed in the hope that it will be useful, but
00011     WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program; if not, write to the Free Software
00017     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019     In addition, as a special exception, the copyright holders give
00020     permission to link the code of this program with any edition of
00021     the Qt library by Trolltech AS, Norway (or with modified versions
00022     of Qt that use the same license as Qt), and distribute linked
00023     combinations including the two.  You must obey the GNU General
00024     Public License in all respects for all of the code used other than
00025     Qt.  If you modify this file, you may extend this exception to
00026     your version of the file, but you are not obligated to do so.  If
00027     you do not wish to do so, delete this exception statement from
00028     your version.
00029 */
00030 #include "email.h"
00031 #include <kdebug.h>
00032 
00033 //-----------------------------------------------------------------------------
00034 QStringList KPIM::splitEmailAddrList(const QString& aStr, bool allowSemicolonAsSeparator)
00035 {
00036   // Features:
00037   // - always ignores quoted characters
00038   // - ignores everything (including parentheses and commas)
00039   //   inside quoted strings
00040   // - supports nested comments
00041   // - ignores everything (including double quotes and commas)
00042   //   inside comments
00043 
00044   QStringList list;
00045 
00046   if (aStr.isEmpty())
00047     return list;
00048 
00049   QString addr;
00050   uint addrstart = 0;
00051   int commentlevel = 0;
00052   bool insidequote = false;
00053 
00054   for (uint index=0; index<aStr.length(); index++) {
00055     // the following conversion to latin1 is o.k. because
00056     // we can safely ignore all non-latin1 characters
00057     switch (aStr[index].latin1()) {
00058     case '"' : // start or end of quoted string
00059       if (commentlevel == 0)
00060         insidequote = !insidequote;
00061       break;
00062     case '(' : // start of comment
00063       if (!insidequote)
00064         commentlevel++;
00065       break;
00066     case ')' : // end of comment
00067       if (!insidequote) {
00068         if (commentlevel > 0)
00069           commentlevel--;
00070         else {
00071           kdDebug(5300) << "Error in address splitting: Unmatched ')'"
00072                         << endl;
00073           return list;
00074         }
00075       }
00076       break;
00077     case '\\' : // quoted character
00078       index++; // ignore the quoted character
00079       break;
00080     case ';' : // fallthrough, if ; is allowed
00081       if ( !allowSemicolonAsSeparator )
00082           break; 
00083     case ',' :
00084       if (!insidequote && (commentlevel == 0)) {
00085         addr = aStr.mid(addrstart, index-addrstart);
00086         kdDebug() << endl << "Adding: " << addr.simplifyWhiteSpace() << endl;
00087         if (!addr.isEmpty())
00088           list += addr.simplifyWhiteSpace();
00089         addrstart = index+1;
00090       }
00091       break;
00092     }
00093   }
00094   // append the last address to the list
00095   if (!insidequote && (commentlevel == 0)) {
00096     addr = aStr.mid(addrstart, aStr.length()-addrstart);
00097     if (!addr.isEmpty())
00098       list += addr.simplifyWhiteSpace();
00099   }
00100   else
00101     kdDebug(5300) << "Error in address splitting: "
00102                   << "Unexpected end of address list"
00103                   << endl;
00104 
00105   return list;
00106 }
00107 
00108 //-----------------------------------------------------------------------------
00109 QCString KPIM::getEmailAddr(const QString& aStr)
00110 {
00111   int a, i, j, len, found = 0;
00112   QChar c;
00113   // Find the '@' in the email address:
00114   a = aStr.find('@');
00115   if (a<0) return aStr.latin1();
00116   // Loop backwards until we find '<', '(', ' ', or beginning of string.
00117   for (i = a - 1; i >= 0; i--) {
00118     c = aStr[i];
00119     if (c == '<' || c == '(' || c == ' ') found = 1;
00120     if (found) break;
00121   }
00122   // Reset found for next loop.
00123   found = 0;
00124   // Loop forwards until we find '>', ')', ' ', or end of string.
00125   for (j = a + 1; j < (int)aStr.length(); j++) {
00126     c = aStr[j];
00127     if (c == '>' || c == ')' || c == ' ') found = 1;
00128     if (found) break;
00129   }
00130   // Calculate the length and return the result.
00131   len = j - (i + 1);
00132   return aStr.mid(i+1,len).latin1();
00133 }
00134 
00135 bool KPIM::getNameAndMail(const QString& aStr, QString& name, QString& mail)
00136 {
00137   name = QString::null;
00138   mail = QString::null;
00139 
00140   const int len=aStr.length();
00141   const char cQuotes = '"';
00142 
00143   bool bInComment = false;
00144   bool bInQuotesOutsideOfEmail = false;
00145   int i=0, iAd=0, iMailStart=0, iMailEnd=0;
00146   QChar c;
00147   unsigned int commentstack = 0;
00148 
00149   // Find the '@' of the email address
00150   // skipping all '@' inside "(...)" comments:
00151   while( i < len ){
00152     c = aStr[i];
00153     if( '(' == c ) commentstack++;
00154     if( ')' == c ) commentstack--;
00155     bInComment = commentstack != 0;
00156     if( '"' == c && !bInComment ) 
00157         bInQuotesOutsideOfEmail = !bInQuotesOutsideOfEmail;
00158 
00159     if( !bInComment && !bInQuotesOutsideOfEmail ){
00160       if( '@' == c ){
00161         iAd = i;
00162         break; // found it
00163       }
00164     }
00165     ++i;
00166   }
00167 
00168   if( !iAd ){
00169     // We suppose the user is typing the string manually and just
00170     // has not finished typing the mail address part.
00171     // So we take everything that's left of the '<' as name and the rest as mail
00172     for( i = 0; len > i; ++i ) {
00173       c = aStr[i];
00174       if( '<' != c )
00175         name.append( c );
00176       else
00177         break;
00178     }
00179     mail = aStr.mid( i+1 );
00180     if ( mail.endsWith( ">" ) )
00181        mail.truncate( mail.length() - 1 );
00182 
00183   }else{
00184 
00185     // Loop backwards until we find the start of the string
00186     // or a ',' that is outside of a comment
00187     //          and outside of quoted text before the leading '<'.
00188     bInComment = false;
00189     bInQuotesOutsideOfEmail = false;
00190     for( i = iAd-1; 0 <= i; --i ) {
00191       c = aStr[i];
00192       if( bInComment ){
00193         if( '(' == c ){
00194           if( !name.isEmpty() )
00195             name.prepend( ' ' );
00196           bInComment = false;
00197         }else{
00198           name.prepend( c ); // all comment stuff is part of the name
00199         }
00200       }else if( bInQuotesOutsideOfEmail ){
00201         if( cQuotes == c )
00202           bInQuotesOutsideOfEmail = false;
00203         else
00204           name.prepend( c );
00205       }else{
00206         // found the start of this addressee ?
00207         if( ',' == c )
00208           break;
00209         // stuff is before the leading '<' ?
00210         if( iMailStart ){
00211           if( cQuotes == c )
00212             bInQuotesOutsideOfEmail = true; // end of quoted text found
00213           else
00214             name.prepend( c );
00215         }else{
00216           switch( c ){
00217             case '<':
00218               iMailStart = i;
00219               break;
00220             case ')':
00221               if( !name.isEmpty() )
00222                 name.prepend( ' ' );
00223               bInComment = true;
00224               break;
00225             default:
00226               if( ' ' != c )
00227                 mail.prepend( c );
00228           }
00229         }
00230       }
00231     }
00232 
00233     name = name.simplifyWhiteSpace();
00234     mail = mail.simplifyWhiteSpace();
00235 
00236     if( mail.isEmpty() )
00237       return false;
00238 
00239     mail.append('@');
00240 
00241     // Loop forward until we find the end of the string
00242     // or a ',' that is outside of a comment
00243     //          and outside of quoted text behind the trailing '>'.
00244     bInComment = false;
00245     bInQuotesOutsideOfEmail = false;
00246     int parenthesesNesting = 0;
00247     for( i = iAd+1; len > i; ++i ) {
00248       c = aStr[i];
00249       if( bInComment ){
00250         if( ')' == c ){
00251           if ( --parenthesesNesting == 0 ) {
00252             bInComment = false;
00253             if( !name.isEmpty() )
00254               name.append( ' ' );
00255           } else {
00256             // nested ")", add it
00257             name.append( ')' ); // name can't be empty here
00258           }
00259         } else {
00260           if( '(' == c ) {
00261             // nested "("
00262             ++parenthesesNesting;
00263           }
00264           name.append( c ); // all comment stuff is part of the name
00265         }
00266       }else if( bInQuotesOutsideOfEmail ){
00267         if( cQuotes == c )
00268           bInQuotesOutsideOfEmail = false;
00269         else
00270           name.append( c );
00271       }else{
00272         // found the end of this addressee ?
00273         if( ',' == c )
00274           break;
00275         // stuff is behind the trailing '>' ?
00276         if( iMailEnd ){
00277           if( cQuotes == c )
00278             bInQuotesOutsideOfEmail = true; // start of quoted text found
00279           else
00280             name.append( c );
00281         }else{
00282           switch( c ){
00283             case '>':
00284               iMailEnd = i;
00285               break;
00286             case '(':
00287               if( !name.isEmpty() )
00288                 name.append( ' ' );
00289               if ( ++parenthesesNesting > 0 )
00290                 bInComment = true;
00291               break;
00292             default:
00293               if( ' ' != c )
00294                 mail.append( c );
00295           }
00296         }
00297       }
00298     }
00299   }
00300 
00301   name = name.simplifyWhiteSpace();
00302   mail = mail.simplifyWhiteSpace();
00303 
00304   return ! (name.isEmpty() || mail.isEmpty());
00305 }
00306 
00307 bool KPIM::compareEmail( const QString& email1, const QString& email2,
00308                          bool matchName )
00309 {
00310   QString e1Name, e1Email, e2Name, e2Email;
00311 
00312   getNameAndMail( email1, e1Name, e1Email );
00313   getNameAndMail( email2, e2Name, e2Email );
00314 
00315   return e1Email == e2Email &&
00316     ( !matchName || ( e1Name == e2Name ) );
00317 }
00318 
00319 
00320 QStringList KPIM::splitEmailAddrList(const QString& aStr)
00321 {
00322     return splitEmailAddrList( aStr, false ); // don't allow ; by default
00323 }
00324 
00325 QString KPIM::quotedName( const QString& fullName )
00326 {
00327   static const QString specials("()<>@,.;:[]");
00328   // add DQUOTE's if necessary:
00329   bool needsQuotes=false;
00330   if ( fullName[0] == '"' && fullName[fullName.length()-1] == '"' ) return fullName;
00331   QString result;
00332   for (unsigned int i=0; i < fullName.length(); i++) {
00333     if ( specials.contains( fullName[i] ) )
00334       needsQuotes = true;
00335     else if ( fullName[i] == '\\' || fullName[i] == '"' ) {
00336       needsQuotes = true;
00337       result += '\\';
00338     }
00339     result += fullName[i];
00340   }
00341 
00342   if (needsQuotes) {
00343     result.insert(0,'"');
00344     result += '"';
00345   }
00346   return result;
00347 
00348 }
KDE Logo
This file is part of the documentation for libkdepim Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Dec 21 14:23:17 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003