/* This file is part of the KDE project Copyright (C) 2004 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Test program for libemailfunctions/email.h #include "email.h" #include #include #include #include #include #include using namespace KPIM; static bool check(const QString& txt, const QString& a, const QString& b) { if (a == b) { kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl; } else { kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl; exit(1); } return true; } static bool check(const QString& txt, const QStringList& a, const QStringList& b) { if ( a.join("\n") == b.join("\n") ) { kdDebug() << txt << " : checking list [ " << a.join( ", " ) << " ] against expected value [ " << b.join( ", " ) << " ]... " << "ok" << endl; } else { kdDebug() << txt << " : checking list [ " << a.join( ",\n" ) << " ] against expected value [ " << b.join( ",\n" ) << " ]... " << "KO !" << endl; exit(1); } return true; } static bool checkGetNameAndEmail(const QString& input, const QString& expName, const QString& expEmail, bool expRetVal) { QString name, email; bool retVal = KPIM::getNameAndMail(input, name, email); check( "getNameAndMail " + input + " retVal", retVal?QString::fromLatin1( "true" ):QString::fromLatin1( "false" ), expRetVal?QString::fromLatin1( "true" ):QString::fromLatin1( "false" ) ); check( "getNameAndMail " + input + " name", name, expName ); check( "getNameAndMail " + input + " email", email, expEmail ); return true; } // convert this to a switch instead but hey, nothing speedy in here is needed but still.. it would be nice static QString emailTestParseResultToString( EmailParseResult errorCode ) { if( errorCode == TooManyAts ) { return "TooManyAts"; } else if( errorCode == TooFewAts ) { return "TooFewAts"; } else if( errorCode == AddressEmpty ) { return "AddressEmpty"; } else if( errorCode == MissingLocalPart ) { return "MissingLocalPart"; } else if( errorCode == MissingDomainPart ) { return "MissingDomainPart"; } else if( errorCode == UnbalancedParens ) { return "UnbalancedParens"; } else if( errorCode == AddressOk ) { return "AddressOk"; } else if( errorCode == UnclosedAngleAddr ) { return "UnclosedAngleAddr"; } else if( errorCode == UnexpectedEnd ) { return "UnexpectedEnd"; } else if( errorCode == UnopenedAngleAddr ) { return "UnopenedAngleAddr"; } else if( errorCode == DisallowedChar ) { return "DisallowedChar"; } else if( errorCode == UnexpectedComma ) { return "UnexpectedComma"; } else if( errorCode == UnbalancedQuote ) { return "UnbalancedQuote"; } else if( errorCode == InvalidDisplayName ) { return "InvalidDisplayName"; } return "unknown error code"; } static QString simpleEmailTestParseResultToString( bool validEmail ) { if ( validEmail ) { return "true"; } return "false"; } static bool checkIsValidEmailAddress( const QString& input, const QString& expErrorCode ) { EmailParseResult errorCode = KPIM::isValidEmailAddress( input ); QString errorC = emailTestParseResultToString( errorCode ); check( "isValidEmailAddress " + input + " errorCode ", errorC , expErrorCode ); return true; } static bool checkIsValidSimpleEmailAddress( const QString& input, const QString& expResult ) { bool validEmail = KPIM::isValidSimpleEmailAddress( input ); QString result = simpleEmailTestParseResultToString( validEmail ); check( "isValidSimpleEmailAddress " + input + " result ", result, expResult ); return true; } static bool checkGetEmailAddress( const QString& input, const QString& expResult ) { QString emailAddress = KPIM::getEmailAddress( input ); QString result = emailAddress; check( "getEmailAddress " + input + " result ", result, expResult ); return true; } static bool checkSplitEmailAddrList( const QString& input, const QStringList& expResult ) { QStringList emailAddresses = KPIM::splitEmailAddrList( input ); check( "splitEmailAddrList( \"" + input + "\" ) result ", emailAddresses, expResult ); return true; } static bool checkNormalizeAddressesAndEncodeIDNs( const QString& input, const QString& expResult ) { QString result = KPIM::normalizeAddressesAndEncodeIDNs( input ); check( "normalizeAddressesAndEncodeIDNs( \"" + input + "\" ) result ", result, expResult ); return true; } static bool checkNormalizeAddressesAndDecodeIDNs( const QString& input, const QString& expResult ) { QString result = KPIM::normalizeAddressesAndDecodeIDNs( input ); check( "normalizeAddressesAndDecodeIDNs( \"" + input + "\" ) result ", result, expResult ); return true; } static bool checkQuoteIfNecessary( const QString& input, const QString& expResult ) { QString result = quoteNameIfNecessary( input ); check( "quoteNameIfNecessary " + input + " result ", result, expResult ); return true; } int main(int argc, char *argv[]) { KApplication::disableAutoDcopRegistration(); KCmdLineArgs::init( argc, argv, "testemail", 0, 0, 0, 0 ); KApplication app( false, false ); // Empty input checkGetNameAndEmail( QString::null, QString::null, QString::null, false ); // Email only checkGetNameAndEmail( "faure@kde.org", QString::null, "faure@kde.org", false ); // Normal case checkGetNameAndEmail( "David Faure ", "David Faure", "faure@kde.org", true ); // Double-quotes checkGetNameAndEmail( "\"Faure, David\" ", "Faure, David", "faure@kde.org", true ); checkGetNameAndEmail( " \"David Faure\"", "David Faure", "faure@kde.org", true ); // Parenthesis checkGetNameAndEmail( "faure@kde.org (David Faure)", "David Faure", "faure@kde.org", true ); checkGetNameAndEmail( "(David Faure) faure@kde.org", "David Faure", "faure@kde.org", true ); checkGetNameAndEmail( "My Name (me) ", "My Name (me)", "me@home.net", true ); // #93513 // Nested parenthesis as per https://intevation.de/roundup/kolab/issue858 checkGetNameAndEmail( "faure@kde.org (David (The Man) Faure)", "David (The Man) Faure", "faure@kde.org", true ); // Double-quotes inside parenthesis checkGetNameAndEmail( "faure@kde.org (David \"Crazy\" Faure)", "David \"Crazy\" Faure", "faure@kde.org", true ); checkGetNameAndEmail( "(David \"Crazy\" Faure) faure@kde.org", "David \"Crazy\" Faure", "faure@kde.org", true ); // Parenthesis inside double-quotes checkGetNameAndEmail( "\"Faure (David)\" ", "Faure (David)", "faure@kde.org", true ); checkGetNameAndEmail( " \"Faure (David)\"", "Faure (David)", "faure@kde.org", true ); // Space in email checkGetNameAndEmail( "David Faure < faure@kde.org >", "David Faure", "faure@kde.org", true ); // Check that '@' in name doesn't confuse it checkGetNameAndEmail( "faure@kde.org (a@b)", "a@b", "faure@kde.org", true ); // Interestingly, this isn't supported. //checkGetNameAndEmail( "\"a@b\" ", "a@b", "faure@kde.org", true ); // While typing, when there's no '@' yet checkGetNameAndEmail( "foo", "foo", QString::null, false ); checkGetNameAndEmail( "foo <", "foo", QString::null, false ); checkGetNameAndEmail( "foo , KHZ ", "Faure, David", "faure@kde.org", true ); // domain literals also need to work checkGetNameAndEmail( "Matt Douhan ", "Matt Douhan", "matt@[123.123.123.123]", true ); // @ inside the comment checkGetNameAndEmail( "\"Matt@Douhan\" ", "Matt@Douhan", "matt@fruitsalad.org", true ); // No '@' checkGetNameAndEmail( "foo ", "foo", "distlist", true ); // To many @'s checkIsValidEmailAddress( "matt@@fruitsalad.org", "TooManyAts" ); // To few @'s checkIsValidEmailAddress( "mattfruitsalad.org", "TooFewAts" ); // An empty string checkIsValidEmailAddress( QString::null , "AddressEmpty" ); // email address starting with a @ checkIsValidEmailAddress( "@mattfruitsalad.org", "MissingLocalPart" ); // make sure that starting @ and an additional @ in the same email address don't conflict // trap the starting @ first and break checkIsValidEmailAddress( "@matt@fruitsalad.org", "MissingLocalPart" ); // email address ending with a @ checkIsValidEmailAddress( "mattfruitsalad.org@", "MissingDomainPart" ); // make sure that ending with@ and an additional @ in the email address don't conflict checkIsValidEmailAddress( "matt@fruitsalad.org@", "MissingDomainPart" ); // unbalanced Parens checkIsValidEmailAddress( "mattjongel)@fruitsalad.org", "UnbalancedParens" ); // unbalanced Parens the other way around checkIsValidEmailAddress( "mattjongel(@fruitsalad.org", "UnbalancedParens" ); // Correct parens just to make sure it works checkIsValidEmailAddress( "matt(jongel)@fruitsalad.org", "AddressOk" ); // Check that anglebrackets are closed checkIsValidEmailAddress( "matt douhanmatt@fruitsalad.org", "UnopenedAngleAddr" ); // Check that angle brackets are closed the other way around, and anglebrackets in domainpart // instead of local part checkIsValidEmailAddress( "matt douhan matt@", "AddressOk" ); // a full email address with comments angle brackets and the works should be valid too checkIsValidEmailAddress( "Matt (jongel) Douhan ", "AddressOk" ); // Double quotes checkIsValidEmailAddress( "\"Matt Douhan\" ", "AddressOk" ); // Double quotes inside parens checkIsValidEmailAddress( "Matt (\"jongel\") Douhan ", "AddressOk" ); // DOuble quotes not closed checkIsValidEmailAddress( "Matt \"jongel Douhan ", "UnbalancedQuote" ); // Parens inside double quotes checkIsValidEmailAddress( "Matt \"(jongel)\" Douhan ", "AddressOk" ); // Space in email checkIsValidEmailAddress( "Matt Douhan < matt@fruitsalad.org >", "AddressOk" ); // @ is allowed inisde doublequotes checkIsValidEmailAddress( "\"matt@jongel\" ", "AddressOk" ); // anglebrackets inside dbl quotes checkIsValidEmailAddress( "\"matt\" ", "AddressOk" ); // a , inside a double quoted string is OK, how do I know this? well Ingo says so // and it makes sense since it is also a seperator of email addresses checkIsValidEmailAddress( "\"Douhan, Matt\" ", "AddressOk" ); // Domains literals also need to work checkIsValidEmailAddress( "Matt Douhan ", "AddressOk" ); // Typo in domain literal address checkIsValidEmailAddress( "Matt Douhan ", "UnexpectedComma" ); // Some more insane tests but still valid so they must work checkIsValidEmailAddress( "Matt Douhan <\"m@att\"@jongel.com>", "AddressOk" ); // BUG 99657 checkIsValidEmailAddress( "matt@jongel.fibbel.com", "AddressOk" ); // BUG 98720 checkIsValidEmailAddress( "mailto:@mydomain", "DisallowedChar" ); // correct error msg when a comma is inside <> checkIsValidEmailAddress( "Matt Douhan ", "UnexpectedComma" ); //several commentlevels checkIsValidEmailAddress( "Matt Douhan (hey(jongel)fibbel) ", "AddressOk" ); // several comment levels and one (the outer) being unbalanced checkIsValidEmailAddress( "Matt Douhan (hey(jongel)fibbel ", "UnbalancedParens" ); // several comment levels and one (the inner) being unbalanced checkIsValidEmailAddress( "Matt Douhan (hey(jongelfibbel) ", "UnbalancedParens" ); // an error inside a double quote is no error checkIsValidEmailAddress ( "Matt Douhan \"(jongel\" ", "AddressOk" ); // inside a quoted string double quotes are only allowed in pairs as per rfc2822 checkIsValidEmailAddress( "Matt Douhan \"jongel\"fibbel\" ", "UnbalancedQuote" ); // a questionmark is valid in an atom checkIsValidEmailAddress ( "Matt? ", "AddressOk" ); // weird but OK checkIsValidEmailAddress( "\"testing, \\\"testing\" ", "AddressOk" ); // escape a quote to many to see if it makes it invalid checkIsValidEmailAddress( "\"testing, \\\"testing\\\" ", "UnbalancedQuote" ); // escape a parens and thus make a comma appear checkIsValidEmailAddress( "Matt (jongel, fibbel\\) ", "UnbalancedParens" ); // several errors inside doublequotes checkIsValidEmailAddress( "Matt \"(jongel,\\\" < fibbel\\\\)\" ", "AddressOk" ); // BUG 105705 checkIsValidEmailAddress( "matt-@fruitsalad.org", "AddressOk" ); // underscore at the end of local part checkIsValidEmailAddress( "matt_@fruitsalad.org", "AddressOk" ); // how about ( comment ) in the domain part checkIsValidEmailAddress( "matt_@(this is a cool host)fruitsalad.org", "AddressOk" ); // To quote rfc2822 the test below is aesthetically displeasing, but perfectly legal. checkIsValidEmailAddress( "Pete(A wonderful \\) chap) ", "AddressOk" ); // quoted pair or not quoted pair checkIsValidEmailAddress( "\"jongel '\\\" fibbel\" ", "AddressOk" ); checkIsValidEmailAddress( "\"jongel '\" fibbel\" ", "UnbalancedQuote" ); // full atext support according to rfc2822 checkIsValidEmailAddress( "!matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "#matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "$matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "%matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "&matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "'matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "*matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "+matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "/matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "=matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "?matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "^matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "_matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "-matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "`matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "{matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "|matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "}matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "~matt@fruitsalad.org", "AddressOk" ); checkIsValidEmailAddress( "matt%matt@fruitsalad.org", "AddressOk" ); //bug 105405 checkIsValidEmailAddress( "[foobar] ", "InvalidDisplayName" ); checkIsValidEmailAddress( "matt \"[foobar]\" Douhan ", "AddressOk" ); checkIsValidEmailAddress( "Matt Douhan ", "TooFewAts" ); // checks for "pure" email addresses in the form of xxx@yyy.tld checkIsValidSimpleEmailAddress( "matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( QString::fromUtf8("test@täst.invalid"), "true" ); // non-ASCII char as first char of IDN checkIsValidSimpleEmailAddress( QString::fromUtf8("i_want@øl.invalid"), "true" ); checkIsValidSimpleEmailAddress( "matt@[123.123.123.123]", "true" ); checkIsValidSimpleEmailAddress( "matt@[3.3.3.3]", "true" ); checkIsValidSimpleEmailAddress( "matt@[4.4.4.4]", "true" ); checkIsValidSimpleEmailAddress( "matt@[192.168.254.254]", "true" ); checkIsValidSimpleEmailAddress( "\"matt\"@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "-matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "\"-matt\"@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "matt@jongel.fibbel.com", "true" ); checkIsValidSimpleEmailAddress( "Matt Douhan ", "false" ); // BUG 105705 checkIsValidSimpleEmailAddress( "matt-@fibbel.com", "true" ); checkIsValidSimpleEmailAddress( "matt@fibbel-is-a-geek.com", "true" ); checkIsValidSimpleEmailAddress( "matt_@fibbel.com", "true" ); // Check the defined chars for atext according to rfc2822 checkIsValidSimpleEmailAddress( "!matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "#matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "$matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "%matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "&matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "'matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "*matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "+matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "/matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "=matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "?matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "^matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "_matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "-matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "`matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "{matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "|matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "}matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "~matt@fruitsalad.org", "true" ); // BUG 108476 checkIsValidSimpleEmailAddress( "foo+matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "bar=matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "jongel-matt@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "matt-@fruitsalad.org", "true" ); // check if the pure email address is wrong checkIsValidSimpleEmailAddress( "mattfruitsalad.org", "false" ); checkIsValidSimpleEmailAddress( "matt@[123.123.123.123", "false" ); checkIsValidSimpleEmailAddress( "matt@123.123.123.123]", "false" ); checkIsValidSimpleEmailAddress( "\"matt@fruitsalad.org", "false" ); checkIsValidSimpleEmailAddress( "matt\"@fruitsalad.org", "false" ); checkIsValidSimpleEmailAddress( QString::null, "false" ); // and here some insane but still valid cases checkIsValidSimpleEmailAddress( "\"m@tt\"@fruitsalad.org", "true" ); checkIsValidSimpleEmailAddress( "matt\"@@\"fruitsalad.org", "false" ); // check the getEmailAddress address method checkGetEmailAddress( "matt@fruitsalad.org", "matt@fruitsalad.org" ); checkGetEmailAddress( "Matt Douhan ", "matt@fruitsalad.org" ); checkGetEmailAddress( "\"Matt Douhan \" ", "matt@fruitsalad.org" ); checkGetEmailAddress( "\"Matt \" ", "matt@fruitsalad.org" ); checkGetEmailAddress( "Matt Douhan (jongel) ", "matt@fruitsalad.org" ); checkGetEmailAddress( "\"Douhan, Matt\" ", "matt@fruitsalad.org" ); checkGetEmailAddress( "\"Matt Douhan (m@tt)\" ", "matt@fruitsalad.org" ); checkGetEmailAddress( "\"Matt Douhan\" (matt ", QString() ); checkGetEmailAddress( "Matt Douhan ", "matt@[123.123.123.123]" ); // check the splitEmailAddrList method checkSplitEmailAddrList( "kloecker@kde.org (Kloecker, Ingo)", QStringList() << "kloecker@kde.org (Kloecker, Ingo)" ); checkSplitEmailAddrList( "Matt Douhan , Foo Bar ", QStringList() << "Matt Douhan " << "Foo Bar " ); checkSplitEmailAddrList( "\"Matt, Douhan\" , Foo Bar ", QStringList() << "\"Matt, Douhan\" " << "Foo Bar " ); // check checkNormalizeAddressesAndEncodeIDNs checkNormalizeAddressesAndEncodeIDNs( "matt@fruitsalad.org", "matt@fruitsalad.org" ); checkNormalizeAddressesAndEncodeIDNs( "Matt Douhan ", "Matt Douhan " ); checkNormalizeAddressesAndEncodeIDNs( "Matt Douhan (jongel) ", "Matt Douhan (jongel) " ); checkNormalizeAddressesAndEncodeIDNs( "Matt Douhan (jongel,fibbel) ", "Matt Douhan (jongel,fibbel) " ); checkNormalizeAddressesAndEncodeIDNs( "matt@fruitsalad.org (jongel,fibbel)", "\"jongel,fibbel\" " ); checkNormalizeAddressesAndEncodeIDNs( "matt@fruitsalad.org (\"jongel,fibbel\")", "\"jongel,fibbel\" " ); // check checkNormalizeAddressesAndDecodeIDNs checkNormalizeAddressesAndDecodeIDNs( "=?us-ascii?Q?Surname=2C=20Name?= ", "\"Surname, Name\" " ); checkNormalizeAddressesAndDecodeIDNs( "=?iso-8859-1?B?5Hf8b2xmLPZBbmRyZWFz?= ", QString::fromUtf8("\"äwüolf,öAndreas\" ") ); // check the "quote if necessary" method checkQuoteIfNecessary( "Matt Douhan", "Matt Douhan"); checkQuoteIfNecessary( "Douhan, Matt", "\"Douhan, Matt\""); checkQuoteIfNecessary( "Matt \"jongel\" Douhan", "\"Matt \\\"jongel\\\" Douhan\""); checkQuoteIfNecessary( "Matt \\\"jongel\\\" Douhan", "\"Matt \\\"jongel\\\" Douhan\""); checkQuoteIfNecessary( "trailing '\\\\' should never occur \\", "\"trailing '\\\\' should never occur \\\""); checkQuoteIfNecessary( "\"don't quote again\"", "\"don't quote again\"" ); checkQuoteIfNecessary( "\"leading double quote", "\"\\\"leading double quote\"" ); checkQuoteIfNecessary( "trailing double quote\"", "\"trailing double quote\\\"\"" ); printf("\nTest OK !\n"); return 0; }