diff options
Diffstat (limited to 'kioslave/smtp')
-rw-r--r-- | kioslave/smtp/CMakeLists.txt | 37 | ||||
-rw-r--r-- | kioslave/smtp/Makefile.am | 37 | ||||
-rw-r--r-- | kioslave/smtp/TODO | 11 | ||||
-rw-r--r-- | kioslave/smtp/capabilities.cc | 143 | ||||
-rw-r--r-- | kioslave/smtp/capabilities.h | 77 | ||||
-rw-r--r-- | kioslave/smtp/command.cc | 606 | ||||
-rw-r--r-- | kioslave/smtp/command.h | 283 | ||||
-rw-r--r-- | kioslave/smtp/compliance.txt | 33 | ||||
-rw-r--r-- | kioslave/smtp/interactivesmtpserver.cc | 127 | ||||
-rw-r--r-- | kioslave/smtp/interactivesmtpserver.h | 121 | ||||
-rw-r--r-- | kioslave/smtp/request.cc | 189 | ||||
-rw-r--r-- | kioslave/smtp/request.h | 100 | ||||
-rw-r--r-- | kioslave/smtp/response.cc | 160 | ||||
-rw-r--r-- | kioslave/smtp/response.h | 125 | ||||
-rw-r--r-- | kioslave/smtp/smtp.cc | 647 | ||||
-rw-r--r-- | kioslave/smtp/smtp.h | 148 | ||||
-rw-r--r-- | kioslave/smtp/smtp.protocol | 16 | ||||
-rw-r--r-- | kioslave/smtp/smtps.protocol | 15 | ||||
-rw-r--r-- | kioslave/smtp/test_commands.cc | 728 | ||||
-rw-r--r-- | kioslave/smtp/test_headergeneration.cc | 86 | ||||
-rw-r--r-- | kioslave/smtp/test_responseparser.cc | 107 | ||||
-rw-r--r-- | kioslave/smtp/transactionstate.cc | 114 | ||||
-rw-r--r-- | kioslave/smtp/transactionstate.h | 185 |
23 files changed, 0 insertions, 4095 deletions
diff --git a/kioslave/smtp/CMakeLists.txt b/kioslave/smtp/CMakeLists.txt deleted file mode 100644 index af475cbc6..000000000 --- a/kioslave/smtp/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -################################################# -# -# (C) 2010-2011 Serghei Amelian -# serghei (DOT) amelian (AT) gmail.com -# -# Improvements and feedback are welcome -# -# This file is released under GPL >= 2 -# -################################################# - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_BINARY_DIR} - ${TDE_INCLUDE_DIR} - ${TQT_INCLUDE_DIRS} -) - -link_directories( - ${TQT_LIBRARY_DIRS} -) - - -##### other data ################################ - -install( FILES smtp.protocol smtps.protocol DESTINATION ${SERVICES_INSTALL_DIR} ) - - -##### kio_smtp (module) ######################### - -set( target kio_smtp ) - -tde_add_kpart( ${target} AUTOMOC - SOURCES smtp.cc request.cc response.cc capabilities.cc command.cc transactionstate.cc - LINK kio-shared ${SASL_LIBRARIES} - DESTINATION ${PLUGIN_INSTALL_DIR} -) diff --git a/kioslave/smtp/Makefile.am b/kioslave/smtp/Makefile.am deleted file mode 100644 index a3ec64a14..000000000 --- a/kioslave/smtp/Makefile.am +++ /dev/null @@ -1,37 +0,0 @@ - -INCLUDES= -I$(srcdir)/../.. -I$(srcdir)/.. $(SSL_INCLUDES) $(all_includes) - -kde_module_LTLIBRARIES = kio_smtp.la - -kio_smtp_la_SOURCES = smtp.cc request.cc response.cc capabilities.cc command.cc transactionstate.cc -kio_smtp_la_LIBADD = $(LIB_KIO) $(SASL2_LIBS) -kio_smtp_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) - -noinst_HEADERS = smtp.h request.h response.h capabilities.h command.h transactionstate.h - -kdelnk_DATA = smtp.protocol smtps.protocol -kdelnkdir = $(kde_servicesdir) - -TESTS = test_headergeneration test_responseparser test_commands - -check_PROGRAMS = $(TESTS) interactivesmtpserver - -test_headergeneration_SOURCES = test_headergeneration.cc -test_headergeneration_LDADD = $(LIB_TDECORE) -test_headergeneration_LDFLAGS = $(all_libraries) - -test_responseparser_SOURCES = test_responseparser.cc -test_responseparser_LDADD = $(LIB_TDECORE) -test_responseparser_LDFLAGS = $(all_libraries) - -test_commands_SOURCES = test_commands.cc -test_commands_LDADD = $(kio_smtp_la_LIBADD) -test_commands_LDFLAGS = $(all_libraries) - -interactivesmtpserver_SOURCES = interactivesmtpserver.cc -interactivesmtpserver_LDADD = $(LIB_QT) -interactivesmtpserver_LDFLAGS = $(all_libraries) -interactivesmtpserver_METASOURCES = AUTO - -messages: - $(XGETTEXT) *.cc -o $(podir)/kio_smtp.pot diff --git a/kioslave/smtp/TODO b/kioslave/smtp/TODO deleted file mode 100644 index cad79f139..000000000 --- a/kioslave/smtp/TODO +++ /dev/null @@ -1,11 +0,0 @@ -1. Double check the error handling and review error message in various - failure modes. -2. Implement the CHUNKING extension (rfc 3030; as soon as I find an - SMTP server that supports it). -3. Better error message (translated standard meanings of the known - response codes, ENHANCEDSTATUSCODES extension (rfc2034)). -4. (KIO) MultiPutJob to support pipelining across messages. -5. Ged rid of slave's header generation after checking who on earth - uses that... - -and further refactoring to make the code pleasant to look at ;-) diff --git a/kioslave/smtp/capabilities.cc b/kioslave/smtp/capabilities.cc deleted file mode 100644 index 0172934dd..000000000 --- a/kioslave/smtp/capabilities.cc +++ /dev/null @@ -1,143 +0,0 @@ -/* -*- c++ -*- - capabilities.cc - - This file is part of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2003 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#include <config.h> - -#include "capabilities.h" - -#include "response.h" - -#include <tqstrlist.h> - -namespace KioSMTP { - - Capabilities Capabilities::fromResponse( const Response & ehlo ) { - Capabilities c; - - // first, check whether the response was valid and indicates success: - if ( !ehlo.isOk() - || ehlo.code() / 10 != 25 // ### restrict to 250 only? - || ehlo.lines().empty() ) - return c; - - QCStringList l = ehlo.lines(); - - for ( QCStringList::const_iterator it = ++l.begin() ; it != l.end() ; ++it ) - c.add( *it ); - - return c; - } - - void Capabilities::add( const TQString & cap, bool replace ) { - TQStringList tokens = TQStringList::split( ' ', cap.upper() ); - if ( tokens.empty() ) - return; - TQString name = tokens.front(); tokens.pop_front(); - add( name, tokens, replace ); - } - - void Capabilities::add( const TQString & name, const TQStringList & args, bool replace ) { - if ( replace ) - mCapabilities[name] = args; - else - mCapabilities[name] += args; - } - - TQString Capabilities::asMetaDataString() const { - TQString result; - for ( TQMap<TQString,TQStringList>::const_iterator it = mCapabilities.begin() ; it != mCapabilities.end() ; ++it ) { - result += it.key(); - if ( !it.data().empty() ) - result += ' ' + it.data().join( " " ); - result += '\n'; - } - return result; - } - - TQString Capabilities::authMethodMetaData() const { - TQStringList sl = saslMethodsQSL(); - TQString result; - for ( TQStringList::const_iterator it = sl.begin() ; it != sl.end() ; ++it ) - result += "SASL/" + *it + '\n'; - return result; - } - - TQStrIList Capabilities::saslMethods() const { - TQStrIList result( true ); // deep copies to be safe - TQStringList sl = saslMethodsQSL(); - for ( TQStringList::const_iterator it = sl.begin() ; it != sl.end() ; ++it ) - result.append( (*it).latin1() ); - return result; - } - - TQString Capabilities::createSpecialResponse( bool tls ) const { - TQStringList result; - if ( tls ) - result.push_back( "STARTTLS" ); - result += saslMethodsQSL(); - if ( have( "PIPELINING" ) ) - result.push_back( "PIPELINING" ); - if ( have( "8BITMIME" ) ) - result.push_back( "8BITMIME" ); - if ( have( "SIZE" ) ) { - bool ok = false; - unsigned int size = mCapabilities["SIZE"].front().toUInt( &ok ); - if ( ok && !size ) - result.push_back( "SIZE=*" ); // any size - else if ( ok ) - result.push_back( "SIZE=" + TQString::number( size ) ); // fixed max - else - result.push_back( "SIZE" ); // indetermined - } - return result.join( " " ); - } - - TQStringList Capabilities::saslMethodsQSL() const { - TQStringList result; - for ( TQMap<TQString,TQStringList>::const_iterator it = mCapabilities.begin() ; it != mCapabilities.end() ; ++it ) { - if ( it.key() == "AUTH" ) - result += it.data(); - else if ( it.key().startsWith( "AUTH=" ) ) { - result.push_back( it.key().mid( tqstrlen("AUTH=") ) ); - result += it.data(); - } - } - result.sort(); - TQStringList::iterator it = result.begin(); - for (TQStringList::iterator ot = it++; it != result.end(); ot = it++) - if (*ot == *it) result.remove(ot); - return result; - } - - - -} // namespace KioSMTP - diff --git a/kioslave/smtp/capabilities.h b/kioslave/smtp/capabilities.h deleted file mode 100644 index 9f9464104..000000000 --- a/kioslave/smtp/capabilities.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- c++ -*- - capabilities.h - - This file is part of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2003 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#ifndef __KIOSMTP_CAPABILITIES_H__ -#define __KIOSMTP_CAPABILITIES_H__ - -#include <tqmap.h> -#include <tqcstring.h> -#include <tqstring.h> -#include <tqstringlist.h> - -class TQStrIList; - -namespace KioSMTP { - - class Response; - - class Capabilities { - public: - Capabilities() {} - - static Capabilities fromResponse( const Response & response ); - - void add( const TQString & cap, bool replace=false ); - void add( const TQString & name, const TQStringList & args, bool replace=false ); - void clear() { mCapabilities.clear(); } - - bool have( const TQString & cap ) const { - return mCapabilities.find( cap.upper() ) != mCapabilities.end(); - } - bool have( const TQCString & cap ) const { return have( TQString( cap.data() ) ); } - bool have( const char * cap ) const { return have( TQString::fromLatin1( cap ) ); } - - TQString asMetaDataString() const; - - TQString authMethodMetaData() const; - TQStrIList saslMethods() const; - - TQString createSpecialResponse( bool tls ) const; - - TQStringList saslMethodsQSL() const; - private: - - TQMap<TQString,TQStringList> mCapabilities; - }; - -} // namespace KioSMTP - -#endif // __KIOSMTP_CAPABILITIES_H__ diff --git a/kioslave/smtp/command.cc b/kioslave/smtp/command.cc deleted file mode 100644 index 2971c291a..000000000 --- a/kioslave/smtp/command.cc +++ /dev/null @@ -1,606 +0,0 @@ -/* -*- c++ -*- - command.cc - - This file is part of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2003 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#include <config.h> - -#include "command.h" - -#include "smtp.h" -#include "response.h" -#include "transactionstate.h" - -#include <kidna.h> -#include <klocale.h> -#include <kdebug.h> -#include <kmdcodec.h> -#include <kio/slavebase.h> // for test_commands, where SMTPProtocol is not derived from TCPSlaveBase - -#include <assert.h> - -namespace KioSMTP { - -#ifdef HAVE_LIBSASL2 -static sasl_callback_t callbacks[] = { - { SASL_CB_ECHOPROMPT, NULL, NULL }, - { SASL_CB_NOECHOPROMPT, NULL, NULL }, - { SASL_CB_GETREALM, NULL, NULL }, - { SASL_CB_USER, NULL, NULL }, - { SASL_CB_AUTHNAME, NULL, NULL }, - { SASL_CB_PASS, NULL, NULL }, - { SASL_CB_CANON_USER, NULL, NULL }, - { SASL_CB_LIST_END, NULL, NULL } -}; -#endif - - // - // Command (base class) - // - - Command::Command( SMTPProtocol * smtp, int flags ) - : mSMTP( smtp ), - mComplete( false ), mNeedResponse( false ), mFlags( flags ) - { - assert( smtp ); - } - - Command::~Command() {} - - bool Command::processResponse( const Response & r, TransactionState * ) { - mComplete = true; - mNeedResponse = false; - return r.isOk(); - } - - void Command::ungetCommandLine( const TQCString &, TransactionState * ) { - mComplete = false; - } - - Command * Command::createSimpleCommand( int which, SMTPProtocol * smtp ) { - switch ( which ) { - case STARTTLS: return new StartTLSCommand( smtp ); - case DATA: return new DataCommand( smtp ); - case NOOP: return new NoopCommand( smtp ); - case RSET: return new RsetCommand( smtp ); - case QUIT: return new QuitCommand( smtp ); - default: return 0; - } - } - - // - // relay methods: - // - - void Command::parseFeatures( const Response & r ) { - mSMTP->parseFeatures( r ); - } - - int Command::startTLS() { - return mSMTP->startTLS(); - } - - bool Command::usingSSL() const { - return mSMTP->usingSSL(); - } - - bool Command::usingTLS() const { - return mSMTP->usingTLS(); - } - - bool Command::haveCapability( const char * cap ) const { - return mSMTP->haveCapability( cap ); - } - - // - // EHLO / HELO - // - - TQCString EHLOCommand::nextCommandLine( TransactionState * ) { - mNeedResponse = true; - mComplete = mEHLONotSupported; - const char * cmd = mEHLONotSupported ? "HELO " : "EHLO " ; - return cmd + KIDNA::toAsciiCString( mHostname ) + "\r\n"; - } - - bool EHLOCommand::processResponse( const Response & r, TransactionState * ) { - mNeedResponse = false; - // "command not {recognized,implemented}" response: - if ( r.code() == 500 || r.code() == 502 ) { - if ( mEHLONotSupported ) { // HELO failed... - mSMTP->error( TDEIO::ERR_INTERNAL_SERVER, - i18n("The server rejected both EHLO and HELO commands " - "as unknown or unimplemented.\n" - "Please contact the server's system administrator.") ); - return false; - } - mEHLONotSupported = true; // EHLO failed, but that's ok. - return true; - } - mComplete = true; - if ( r.code() / 10 == 25 ) { // 25x: success - parseFeatures( r ); - return true; - } - mSMTP->error( TDEIO::ERR_UNKNOWN, - i18n("Unexpected server response to %1 command.\n%2") - .arg( mEHLONotSupported ? "HELO" : "EHLO" ) - .arg( r.errorMessage() ) ); - return false; - } - - // - // STARTTLS - rfc 3207 - // - - TQCString StartTLSCommand::nextCommandLine( TransactionState * ) { - mComplete = true; - mNeedResponse = true; - return "STARTTLS\r\n"; - } - - bool StartTLSCommand::processResponse( const Response & r, TransactionState * ) { - mNeedResponse = false; - if ( r.code() != 220 ) { - mSMTP->error( r.errorCode(), - i18n("Your SMTP server does not support TLS. " - "Disable TLS, if you want to connect " - "without encryption.") ); - return false; - } - - int tlsrc = startTLS(); - - if ( tlsrc == 1 ) - return true; - - if ( tlsrc != -3 ) - //kdDebug(7112) << "TLS negotiation failed!" << endl; - mSMTP->messageBox(TDEIO::SlaveBase::Information, - i18n("Your SMTP server claims to " - "support TLS, but negotiation " - "was unsuccessful.\nYou can " - "disable TLS in KDE using the " - "crypto settings module."), - i18n("Connection Failed")); - return false; - } - - -#define SASLERROR mSMTP->error(TDEIO::ERR_COULD_NOT_AUTHENTICATE, \ - i18n("An error occured during authentication: %1").arg \ - ( TQString::fromUtf8( sasl_errdetail( conn ) ))); - - // - // AUTH - rfc 2554 - // - AuthCommand::AuthCommand( SMTPProtocol * smtp, - const char *mechanisms, - const TQString &aFQDN, - TDEIO::AuthInfo &ai ) - : Command( smtp, CloseConnectionOnError|OnlyLastInPipeline ), - mAi( &ai ), - mFirstTime( true ) - { -#ifdef HAVE_LIBSASL2 - int result; - mMechusing = 0; - conn = 0; - client_interact = 0; - mOut = 0; mOutlen = 0; - mOneStep = false; - - result = sasl_client_new( "smtp", aFQDN.latin1(), - 0, 0, callbacks, 0, &conn ); - if ( result != SASL_OK ) { - SASLERROR - return; - } - do { - result = sasl_client_start(conn, mechanisms, - &client_interact, &mOut, &mOutlen, &mMechusing); - - if (result == SASL_INTERACT) - if ( !saslInteract( client_interact ) ) { - return; - }; - } while ( result == SASL_INTERACT ); - if ( result != SASL_CONTINUE && result != SASL_OK ) { - SASLERROR - return; - } - if ( result == SASL_OK ) mOneStep = true; - kdDebug(7112) << "Mechanism: " << mMechusing << " one step: " << mOneStep << endl; -#else - mSMTP->error(TDEIO::ERR_COULD_NOT_AUTHENTICATE, - i18n("Authentication support is not compiled into kio_smtp.")); -#endif - } - - AuthCommand::~AuthCommand() - { -#ifdef HAVE_LIBSASL2 - if ( conn ) { - kdDebug(7112) << "dispose sasl connection" << endl; - sasl_dispose( &conn ); - conn = 0; - } -#endif - } - - bool AuthCommand::saslInteract( void *in ) - { -#ifdef HAVE_LIBSASL2 - kdDebug(7112) << "saslInteract: " << endl; - sasl_interact_t *interact = ( sasl_interact_t * ) in; - - //some mechanisms do not require username && pass, so don't need a popup - //window for getting this info - for ( ; interact->id != SASL_CB_LIST_END; interact++ ) { - if ( interact->id == SASL_CB_AUTHNAME || - interact->id == SASL_CB_PASS ) { - - if ( mAi->username.isEmpty() || mAi->password.isEmpty()) { - if (!mSMTP->openPassDlg(*mAi)) { - mSMTP->error(TDEIO::ERR_ABORTED, i18n("No authentication details supplied.")); - return false; - } - } - break; - } - } - - interact = ( sasl_interact_t * ) in; - while( interact->id != SASL_CB_LIST_END ) { - switch( interact->id ) { - case SASL_CB_USER: - case SASL_CB_AUTHNAME: - kdDebug(7112) << "SASL_CB_[USER|AUTHNAME]: " << mAi->username << endl; - interact->result = strdup( mAi->username.utf8() ); - interact->len = strlen( (const char *) interact->result ); - break; - case SASL_CB_PASS: - kdDebug(7112) << "SASL_CB_PASS: [HIDDEN]" << endl; - interact->result = strdup( mAi->password.utf8() ); - interact->len = strlen( (const char *) interact->result ); - break; - default: - interact->result = NULL; interact->len = 0; - break; - } - interact++; - } - return true; -#else - return false; -#endif - } - - bool AuthCommand::doNotExecute( const TransactionState * ) const { - return !mMechusing; - } - - void AuthCommand::ungetCommandLine( const TQCString & s, TransactionState * ) { - mUngetSASLResponse = s; - mComplete = false; - } - - TQCString AuthCommand::nextCommandLine( TransactionState * ) { - mNeedResponse = true; - TQCString cmd; -#ifdef HAVE_LIBSASL2 - TQByteArray tmp, challenge; - if ( !mUngetSASLResponse.isNull() ) { - // implement un-ungetCommandLine - cmd = mUngetSASLResponse; - mUngetSASLResponse = 0; - } else if ( mFirstTime ) { - TQString firstCommand = "AUTH " + TQString::fromLatin1( mMechusing ); - - tmp.setRawData( mOut, mOutlen ); - KCodecs::base64Encode( tmp, challenge ); - tmp.resetRawData( mOut, mOutlen ); - if ( !challenge.isEmpty() ) { - firstCommand += " "; - firstCommand += TQString::fromLatin1( challenge.data(), challenge.size() ); - } - cmd = firstCommand.latin1(); - - if ( mOneStep ) mComplete = true; - } else { -// kdDebug(7112) << "SS: '" << mLastChallenge << "'" << endl; - tmp.setRawData( mLastChallenge.data(), mLastChallenge.length() ); - KCodecs::base64Decode( tmp, challenge ); - tmp.resetRawData( mLastChallenge.data(), mLastChallenge.length() ); - int result; - do { - result = sasl_client_step(conn, challenge.isEmpty() ? 0 : challenge.data(), - challenge.size(), - &client_interact, - &mOut, &mOutlen); - if (result == SASL_INTERACT) - if ( !saslInteract( client_interact ) ) { - return ""; - }; - } while ( result == SASL_INTERACT ); - if ( result != SASL_CONTINUE && result != SASL_OK ) { - kdDebug(7112) << "sasl_client_step failed with: " << result << endl; - SASLERROR - return ""; - } - tmp.setRawData( mOut, mOutlen ); - cmd = KCodecs::base64Encode( tmp ); - tmp.resetRawData( mOut, mOutlen ); - -// kdDebug(7112) << "CC: '" << cmd << "'" << endl; - mComplete = ( result == SASL_OK ); - } -#endif //HAVE_LIBSASL2 - cmd += "\r\n"; - return cmd; - } - - bool AuthCommand::processResponse( const Response & r, TransactionState * ) { - if ( !r.isOk() ) { - if ( mFirstTime ) - if ( haveCapability( "AUTH" ) ) - mSMTP->error( TDEIO::ERR_COULD_NOT_LOGIN, - i18n("Your SMTP server does not support %1.\nChoose a different authentication method.\n%2") - .arg( mMechusing ).arg( r.errorMessage() ) ); - else - mSMTP->error( TDEIO::ERR_COULD_NOT_LOGIN, - i18n("Your SMTP server does not support authentication.\n" - " %2").arg( r.errorMessage() ) ); - else - mSMTP->error( TDEIO::ERR_COULD_NOT_LOGIN, - i18n("Authentication failed.\n" - "Most likely the password is wrong.\n" - "%1").arg( r.errorMessage() ) ); - return false; - } - mFirstTime = false; - mLastChallenge = r.lines().front(); // ### better join all lines with \n? - mNeedResponse = false; - return true; - } - - // - // MAIL FROM: - // - - TQCString MailFromCommand::nextCommandLine( TransactionState * ) { - mComplete = true; - mNeedResponse = true; - TQCString cmdLine = "MAIL FROM:<" + mAddr + '>'; - if ( m8Bit && haveCapability("8BITMIME") ) - cmdLine += " BODY=8BITMIME"; - if ( mSize && haveCapability("SIZE") ) - cmdLine += " SIZE=" + TQCString().setNum( mSize ); - return cmdLine + "\r\n"; - } - - bool MailFromCommand::processResponse( const Response & r, TransactionState * ts ) { - assert( ts ); - mNeedResponse = false; - - if ( r.code() == 250 ) - return true; - - ts->setMailFromFailed( mAddr, r ); - return false; - } - - // - // RCPT TO: - // - - TQCString RcptToCommand::nextCommandLine( TransactionState * ) { - mComplete = true; - mNeedResponse = true; - return "RCPT TO:<" + mAddr + ">\r\n"; - } - - bool RcptToCommand::processResponse( const Response & r, TransactionState * ts ) { - assert( ts ); - mNeedResponse = false; - - if ( r.code() == 250 ) { - ts->setRecipientAccepted(); - return true; - } - - ts->addRejectedRecipient( mAddr, r.errorMessage() ); - return false; - } - - // - // DATA (only initial processing!) - // - - TQCString DataCommand::nextCommandLine( TransactionState * ts ) { - assert( ts ); - mComplete = true; - mNeedResponse = true; - ts->setDataCommandIssued( true ); - return "DATA\r\n"; - } - - void DataCommand::ungetCommandLine( const TQCString &, TransactionState * ts ) { - assert( ts ); - mComplete = false; - ts->setDataCommandIssued( false ); - } - - bool DataCommand::processResponse( const Response & r, TransactionState * ts ) { - assert( ts ); - mNeedResponse = false; - - if ( r.code() == 354 ) { - ts->setDataCommandSucceeded( true, r ); - return true; - } - - ts->setDataCommandSucceeded( false, r ); - return false; - } - - // - // DATA (data transfer) - // - void TransferCommand::ungetCommandLine( const TQCString & cmd, TransactionState * ) { - if ( cmd.isEmpty() ) - return; // don't change state when we can't detect the unget in - // the next nextCommandLine !! - mWasComplete = mComplete; - mComplete = false; - mNeedResponse = false; - mUngetBuffer = cmd; - } - - bool TransferCommand::doNotExecute( const TransactionState * ts ) const { - assert( ts ); - return ts->failed(); - } - - TQCString TransferCommand::nextCommandLine( TransactionState * ts ) { - assert( ts ); // let's rely on it ( at least for the moment ) - assert( !isComplete() ); - assert( !ts->failed() ); - - static const TQCString dotCRLF = ".\r\n"; - static const TQCString CRLFdotCRLF = "\r\n.\r\n"; - - if ( !mUngetBuffer.isEmpty() ) { - const TQCString ret = mUngetBuffer; - mUngetBuffer = 0; - if ( mWasComplete ) { - mComplete = true; - mNeedResponse = true; - } - return ret; // don't prepare(), it's slave-generated or already prepare()d - } - - // normal processing: - - kdDebug(7112) << "requesting data" << endl; - mSMTP->dataReq(); - TQByteArray ba; - int result = mSMTP->readData( ba ); - kdDebug(7112) << "got " << result << " bytes" << endl; - if ( result > 0 ) - return prepare( ba ); - else if ( result < 0 ) { - ts->setFailedFatally( TDEIO::ERR_INTERNAL, - i18n("Could not read data from application.") ); - mComplete = true; - mNeedResponse = true; - return 0; - } - mComplete = true; - mNeedResponse = true; - return mLastChar == '\n' ? dotCRLF : CRLFdotCRLF ; - } - - bool TransferCommand::processResponse( const Response & r, TransactionState * ts ) { - mNeedResponse = false; - assert( ts ); - ts->setComplete(); - if ( !r.isOk() ) { - ts->setFailed(); - mSMTP->error( r.errorCode(), - i18n("The message content was not accepted.\n" - "%1").arg( r.errorMessage() ) ); - return false; - } - return true; - } - - static TQCString dotstuff_lf2crlf( const TQByteArray & ba, char & last ) { - TQCString result( ba.size() * 2 + 1 ); // worst case: repeated "[.]\n" - const char * s = ba.data(); - const char * const send = ba.data() + ba.size(); - char * d = result.data(); - - while ( s < send ) { - const char ch = *s++; - if ( ch == '\n' && last != '\r' ) - *d++ = '\r'; // lf2crlf - else if ( ch == '.' && last == '\n' ) - *d++ = '.'; // dotstuff - last = *d++ = ch; - } - - result.truncate( d - result.data() ); - return result; - } - - TQCString TransferCommand::prepare( const TQByteArray & ba ) { - if ( ba.isEmpty() ) - return 0; - if ( mSMTP->metaData("lf2crlf+dotstuff") == "slave" ) { - kdDebug(7112) << "performing dotstuffing and LF->CRLF transformation" << endl; - return dotstuff_lf2crlf( ba, mLastChar ); - } else { - mLastChar = ba[ ba.size() - 1 ]; - return TQCString( ba.data(), ba.size() + 1 ); - } - } - - // - // NOOP - // - - TQCString NoopCommand::nextCommandLine( TransactionState * ) { - mComplete = true; - mNeedResponse = true; - return "NOOP\r\n"; - } - - // - // RSET - // - - TQCString RsetCommand::nextCommandLine( TransactionState * ) { - mComplete = true; - mNeedResponse = true; - return "RSET\r\n"; - } - - // - // QUIT - // - - TQCString QuitCommand::nextCommandLine( TransactionState * ) { - mComplete = true; - mNeedResponse = true; - return "QUIT\r\n"; - } - -} // namespace KioSMTP - diff --git a/kioslave/smtp/command.h b/kioslave/smtp/command.h deleted file mode 100644 index ed3e1fb66..000000000 --- a/kioslave/smtp/command.h +++ /dev/null @@ -1,283 +0,0 @@ -/* -*- c++ -*- - command.h - - This file is part of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2003 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#ifndef __KIOSMTP_COMMAND_H__ -#define __KIOSMTP_COMMAND_H__ - - -#include <tqstring.h> -#include <tqcstring.h> - -#ifdef HAVE_LIBSASL2 -extern "C" { -#include <sasl/sasl.h> -} -#endif - -#include <kio/authinfo.h> - -class SMTPProtocol; -class TQStrIList; - -namespace KioSMTP { - - class Response; - class TransactionState; - - /** - * @short Represents an SMTP command - * - * Semantics: A command consists of a series of "command lines" - * (though that's stretching it a bit for @ref TransferJob and @ref - * AuthCommand) and responses. There's typically one response for - * one command line and the command is completed. - * - * However, some commands consist of a dialog (command line, - * response, command line, response,...) where each successive - * command line is dependant on the previously received response - * (and thus those commands are not pipelinable). That's why each - * command signals completion by having it's @ref #isComplete() - * method return true @em after the last command line to be sent, - * but @em before the last response to receive. @ref AuthCommand is - * the principal representative of this kind of command. Because - * @ref EHLOCommand automatically falls back to HELO in case EHLO - * isn't supported, it is also of this kind. If completion is - * signalled before the first command line is issued, it is not to - * be executed at all. - * - * Other commands need to send multiple "command lines" before - * receiving a single (final) response. @ref TransferCommand is the - * only representative of this kind of "command". That's why each - * command signals whether it now expects a response before being - * able to issue the next command line (if any) by having it's @ref - * #needsResponse() method return true. - * - * Commands whose @ref #nextCommandLine() does not support being - * called multiple times in a row without changing command state, - * must reimplement @ref #ungetCommandLine(). - **/ - class Command { - public: - enum Flags { - OnlyLastInPipeline = 1, - OnlyFirstInPipeline = 2, - CloseConnectionOnError = 4 - }; - - Command( SMTPProtocol * smtp, int flags=0 ); - virtual ~Command(); - - enum Type { - STARTTLS, DATA, NOOP, RSET, QUIT - }; - - static Command * createSimpleCommand( int which, SMTPProtocol * smtp ); - - virtual TQCString nextCommandLine( TransactionState * ts=0 ) = 0; - /* Reimplement this if your @ref #nextCommandLine() implementation - changes state other than @ref mComplete. The default - implementation just resets @ref mComplete to false. */ - virtual void ungetCommandLine( const TQCString & cmdLine, TransactionState * ts=0 ); - /* Reimplement this if your command need more sophisicated - response processing than just checking for @ref - Response::isOk(). The default implementation sets @ref - mComplete to true, @ref mNeedResponse to false and returns - whether the response isOk(). */ - virtual bool processResponse( const Response & response, TransactionState * ts=0 ); - - virtual bool doNotExecute( const TransactionState * ) const { return false; } - - bool isComplete() const { return mComplete; } - /** @return whether the command expects a response now. Some - commands (most notably AUTH) may consist of a series of - commands and associated responses until they are - complete. Others (most notably @ref TransferCommand usually - send multiple "command lines" before expecting a response. */ - bool needsResponse() const { return mNeedResponse; } - /** @return whether an error in executing this command is so fatal - that closing the connection is the only option */ - bool closeConnectionOnError() const { - return mFlags & CloseConnectionOnError; - } - bool mustBeLastInPipeline() const { - return mFlags & OnlyLastInPipeline; - } - bool mustBeFirstInPipeline() const { - return mFlags & OnlyFirstInPipeline; - } - - protected: - SMTPProtocol * mSMTP; - bool mComplete; - bool mNeedResponse; - const int mFlags; - - protected: - // only relay methods to enable access to slave-protected methods - // for subclasses of Command: - void parseFeatures( const Response & r ); - int startTLS(); - bool usingSSL() const; - bool usingTLS() const; - bool haveCapability( const char * cap ) const; - }; - - class EHLOCommand : public Command { - public: - EHLOCommand( SMTPProtocol * smtp, const TQString & hostname ) - : Command( smtp, CloseConnectionOnError|OnlyLastInPipeline ), - mEHLONotSupported( false ), - mHostname( hostname.stripWhiteSpace() ) {} - - TQCString nextCommandLine( TransactionState * ); - bool processResponse( const Response & response, TransactionState * ); - private: - bool mEHLONotSupported; - TQString mHostname; - }; - - class StartTLSCommand : public Command { - public: - StartTLSCommand( SMTPProtocol * smtp ) - : Command( smtp, CloseConnectionOnError|OnlyLastInPipeline ) {} - - TQCString nextCommandLine( TransactionState * ); - bool processResponse( const Response & response, TransactionState * ); - }; - - class AuthCommand : public Command { - public: - AuthCommand( SMTPProtocol * smtp, const char *mechanisms, - const TQString &aFQDN, TDEIO::AuthInfo &ai ); - ~AuthCommand(); - bool doNotExecute( const TransactionState * ts ) const; - TQCString nextCommandLine( TransactionState * ); - void ungetCommandLine( const TQCString & cmdLine, TransactionState * ); - bool processResponse( const Response & response, TransactionState * ); - private: - bool saslInteract( void *in ); - -#ifdef HAVE_LIBSASL2 - sasl_conn_t *conn; - sasl_interact_t *client_interact; -#endif - const char *mOut, *mMechusing; - uint mOutlen; - bool mOneStep; - - TDEIO::AuthInfo *mAi; - TQCString mLastChallenge; - TQCString mUngetSASLResponse; - bool mFirstTime; - }; - - class MailFromCommand : public Command { - public: - MailFromCommand( SMTPProtocol * smtp, const TQCString & addr, - bool eightBit=false, unsigned int size=0 ) - : Command( smtp ), mAddr( addr ), m8Bit( eightBit ), mSize( size ) {} - - TQCString nextCommandLine( TransactionState * ); - bool processResponse( const Response & response, TransactionState * ); - private: - TQCString mAddr; - bool m8Bit; - unsigned int mSize; - }; - - class RcptToCommand : public Command { - public: - RcptToCommand( SMTPProtocol * smtp, const TQCString & addr ) - : Command( smtp ), mAddr( addr ) {} - - TQCString nextCommandLine( TransactionState * ); - bool processResponse( const Response & response, TransactionState * ); - private: - TQCString mAddr; - }; - - /** Handles only the initial intermediate response and compltetes at - the point where the mail contents need to be sent */ - class DataCommand : public Command { - public: - DataCommand( SMTPProtocol * smtp ) - : Command( smtp, OnlyLastInPipeline ) {} - - TQCString nextCommandLine( TransactionState * ); - void ungetCommandLine( const TQCString & cmd, TransactionState * ts ); - bool processResponse( const Response & response, TransactionState * ); - }; - - /** Handles the data transfer following a successful DATA command */ - class TransferCommand : public Command { - public: - TransferCommand( SMTPProtocol * smtp, const TQCString & initialBuffer ) - : Command( smtp, OnlyFirstInPipeline ), - mUngetBuffer( initialBuffer ), mLastChar( '\n' ), mWasComplete( false ) {} - - bool doNotExecute( const TransactionState * ts ) const; - TQCString nextCommandLine( TransactionState * ); - void ungetCommandLine( const TQCString & cmd, TransactionState * ts ); - bool processResponse( const Response & response, TransactionState * ); - private: - TQCString prepare( const TQByteArray & ba ); - TQCString mUngetBuffer; - char mLastChar; - bool mWasComplete; // ... before ungetting - }; - - class NoopCommand : public Command { - public: - NoopCommand( SMTPProtocol * smtp ) - : Command( smtp, OnlyLastInPipeline ) {} - - TQCString nextCommandLine( TransactionState * ); - }; - - class RsetCommand : public Command { - public: - RsetCommand( SMTPProtocol * smtp ) - : Command( smtp, CloseConnectionOnError ) {} - - TQCString nextCommandLine( TransactionState * ); - }; - - class QuitCommand : public Command { - public: - QuitCommand( SMTPProtocol * smtp ) - : Command( smtp, CloseConnectionOnError|OnlyLastInPipeline ) {} - - TQCString nextCommandLine( TransactionState * ); - }; - -} // namespace KioSMTP - -#endif // __KIOSMTP_COMMAND_H__ diff --git a/kioslave/smtp/compliance.txt b/kioslave/smtp/compliance.txt deleted file mode 100644 index b6b9874c8..000000000 --- a/kioslave/smtp/compliance.txt +++ /dev/null @@ -1,33 +0,0 @@ -The SMTP kioslave currently conforms to the following SMTP-related RFCs: - -Base Spec: -2821 Simple Mail Transfer Protocol. J. Klensin, Ed.. April 2001. - (Format: TXT=192504 bytes) (Obsoletes RFC0821, RFC0974, RFC1869) - (Status: PROPOSED STANDARD) - -Encryption/Auth: -3207 SMTP Service Extension for Secure SMTP over Transport Layer - Security. P. Hoffman. February 2002. (Format: TXT=18679 bytes) - (Obsoletes RFC2487) (Status: PROPOSED STANDARD) - -2554 SMTP Service Extension for Authentication. J. Myers. March 1999. - (Format: TXT=20534 bytes) (Status: PROPOSED STANDARD) -(with all SASL mechanisms supported by KDESasl) - -General: -1652 SMTP Service Extension for 8bit-MIMEtransport. J. Klensin, N. - Freed, M. Rose, E. Stefferud, D. Crocker. July 1994. (Format: - TXT=11842 bytes) (Obsoletes RFC1426) (Status: DRAFT STANDARD) - -1870 SMTP Service Extension for Message Size Declaration. J. Klensin, - N. Freed, K. Moore. November 1995. (Format: TXT=18226 bytes) - (Obsoletes RFC1653) (Also STD0010) (Status: STANDARD) - -2920 SMTP Service Extension for Command Pipelining. N. Freed. - September 2000. (Format: TXT=17065 bytes) (Obsoletes RFC2197) (Also - STD0060) (Status: STANDARD) - -Known shortcomings: -- Doesn't enforce the CRLF lineending convention on user-supplied data. -- Due to the lack of a Mulit_Put_ in the KIO infrastructure, pipelining - across messages isn't supported. diff --git a/kioslave/smtp/interactivesmtpserver.cc b/kioslave/smtp/interactivesmtpserver.cc deleted file mode 100644 index 54c0b58be..000000000 --- a/kioslave/smtp/interactivesmtpserver.cc +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- c++ -*- - interactivesmtpserver.cc - - Code based on the serverSocket example by Jesper Pedersen. - - This file is part of the testsuite of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2004 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#include <config.h> - -#include <tqserversocket.h> -#include <tqsocket.h> -#include <tqwidget.h> -#include <tqapplication.h> -#include <tqhostaddress.h> -#include <tqtextedit.h> -#include <tqlineedit.h> -#include <tqlabel.h> -#include <tqstring.h> -#include <tqlayout.h> -#include <tqpushbutton.h> - -#include <cassert> - -#include "interactivesmtpserver.h" - -static const TQHostAddress localhost( 0x7f000001 ); // 127.0.0.1 - -InteractiveSMTPServerWindow::~InteractiveSMTPServerWindow() { - if ( mSocket ) { - mSocket->close(); - if ( mSocket->state() == TQSocket::Closing ) - connect( mSocket, TQT_SIGNAL(delayedCloseFinished()), - mSocket, TQT_SLOT(deleteLater()) ); - else - mSocket->deleteLater(); - mSocket = 0; - } -} - -void InteractiveSMTPServerWindow::slotSendResponse() -{ - const TQString line = mLineEdit->text(); - mLineEdit->clear(); - TQTextStream s( mSocket ); - s << line + "\r\n"; - slotDisplayServer( line ); -} - -InteractiveSMTPServer::InteractiveSMTPServer( TQObject* parent ) - : TQServerSocket( localhost, 2525, 1, parent ) -{ -} - -int main( int argc, char * argv[] ) { - TQApplication app( argc, argv ); - - InteractiveSMTPServer server; - - tqDebug( "Server should now listen on localhost:2525" ); - tqDebug( "Hit CTRL-C to quit." ); - return app.exec(); -}; - - -InteractiveSMTPServerWindow::InteractiveSMTPServerWindow( TQSocket * socket, TQWidget * parent, const char * name, WFlags f ) - : TQWidget( parent, name, f ), mSocket( socket ) -{ - TQPushButton * but; - assert( socket ); - - TQVBoxLayout * vlay = new TQVBoxLayout( this, 6 ); - - mTextEdit = new TQTextEdit( this ); - mTextEdit->setTextFormat( TQTextEdit::LogText ); - vlay->addWidget( mTextEdit, 1 ); - - TQHBoxLayout * hlay = new TQHBoxLayout( vlay ); - - mLineEdit = new TQLineEdit( this ); - but = new TQPushButton( "&Send", this ); - hlay->addWidget( new TQLabel( mLineEdit, "&Response:", this ) ); - hlay->addWidget( mLineEdit, 1 ); - hlay->addWidget( but ); - - connect( mLineEdit, TQT_SIGNAL(returnPressed()), TQT_SLOT(slotSendResponse()) ); - connect( but, TQT_SIGNAL(clicked()), TQT_SLOT(slotSendResponse()) ); - - but = new TQPushButton( "&Close Connection", this ); - vlay->addWidget( but ); - - connect( but, TQT_SIGNAL(clicked()), TQT_SLOT(slotConnectionClosed()) ); - - connect( socket, TQT_SIGNAL(connectionClosed()), TQT_SLOT(slotConnectionClosed()) ); - connect( socket, TQT_SIGNAL(error(int)), TQT_SLOT(slotError(int)) ); - connect( socket, TQT_SIGNAL(readyRead()), TQT_SLOT(slotReadyRead()) ); - - mLineEdit->setText( "220 hi there" ); - mLineEdit->setFocus(); -} - -#include "interactivesmtpserver.moc" diff --git a/kioslave/smtp/interactivesmtpserver.h b/kioslave/smtp/interactivesmtpserver.h deleted file mode 100644 index 39a07f6a9..000000000 --- a/kioslave/smtp/interactivesmtpserver.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef INTERACTIVESMTPSERVER_H -#define INTERACTIVESMTPSERVER_H - -/* -*- c++ -*- - interactivesmtpserver.h - - Code based on the serverSocket example by Jesper Pedersen. - - This file is part of the testsuite of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2004 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#include <tqwidget.h> - - -static TQString err2str( int err ) { - switch ( err ) { - case TQSocket::ErrConnectionRefused: return "Connection refused"; - case TQSocket::ErrHostNotFound: return "Host not found"; - case TQSocket::ErrSocketRead: return "Failed to read from socket"; - default: return "Unknown error"; - } -} - - -static TQString escape( TQString s ) { - return s - .replace( '&', "&" ) - .replace( '>', ">" ) - .replace( '<', "<" ) - .replace( '"', """ ) - ; -} - - -static TQString trim( const TQString & s ) { - if ( s.endsWith( "\r\n" ) ) - return s.left( s.length() - 2 ); - if ( s.endsWith( "\r" ) || s.endsWith( "\n" ) ) - return s.left( s.length() - 1 ); - return s; -} - - -class InteractiveSMTPServerWindow : public TQWidget { - Q_OBJECT -public: - InteractiveSMTPServerWindow( TQSocket * socket, TQWidget * parent=0, const char * name=0, WFlags f=0 ); - ~InteractiveSMTPServerWindow(); - -public slots: - void slotSendResponse(); - void slotDisplayClient( const TQString & s ) { - mTextEdit->append( "C:" + escape(s) ); - } - void slotDisplayServer( const TQString & s ) { - mTextEdit->append( "S:" + escape(s) ); - } - void slotDisplayMeta( const TQString & s ) { - mTextEdit->append( "<font color=\"red\">" + escape(s) + "</font>" ); - } - void slotReadyRead() { - while ( mSocket->canReadLine() ) - slotDisplayClient( trim( mSocket->readLine() ) ); - } - void slotError( int err ) { - slotDisplayMeta( TQString( "E: %1 (%2)" ).arg( err2str( err ) ).arg( err ) ); - } - void slotConnectionClosed() { - slotDisplayMeta( "Connection closed by peer" ); - } - void slotCloseConnection() { - mSocket->close(); - } -private: - TQSocket * mSocket; - TQTextEdit * mTextEdit; - TQLineEdit * mLineEdit; -}; - -class InteractiveSMTPServer : public TQServerSocket { - Q_OBJECT -public: - InteractiveSMTPServer( TQObject * parent=0 ); - ~InteractiveSMTPServer() {} - - /*! \reimp */ - void newConnection( int fd ) { - TQSocket * socket = new TQSocket(); - socket->setSocket( fd ); - InteractiveSMTPServerWindow * w = new InteractiveSMTPServerWindow( socket ); - w->show(); - } -}; - - -#endif diff --git a/kioslave/smtp/request.cc b/kioslave/smtp/request.cc deleted file mode 100644 index 84a1663f8..000000000 --- a/kioslave/smtp/request.cc +++ /dev/null @@ -1,189 +0,0 @@ -/* -*- c++ -*- - request.cc - - This file is part of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2003 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#include <config.h> - -#include "request.h" - -#include <kurl.h> -#include <kidna.h> -#include <kmdcodec.h> -#include <kdebug.h> - -#include <assert.h> - -namespace KioSMTP { - - Request Request::fromURL( const KURL & url ) { - Request request; - - const TQStringList query = TQStringList::split( '&', url.query().mid(1) ); -#ifndef NDEBUG - kdDebug(7112) << "Parsing request from query:\n" + query.join("\n" ) << endl; -#endif - for ( TQStringList::const_iterator it = query.begin() ; it != query.end() ; ++it ) { - int equalsPos = (*it).find( '=' ); - if ( equalsPos <= 0 ) - continue; - - const TQString key = (*it).left( equalsPos ).lower(); - const TQString value = KURL::decode_string( (*it).mid( equalsPos + 1 ) ); - - if ( key == "to" ) - request.addTo( value ); - else if ( key == "cc" ) - request.addCc( value ); - else if ( key == "bcc" ) - request.addBcc( value ); - else if ( key == "headers" ) { - request.setEmitHeaders( value == "0" ); - request.setEmitHeaders( false ); // ### ??? - } - else if ( key == "subject" ) - request.setSubject( value ); - else if ( key == "from" ) - request.setFromAddress( value ); - else if ( key == "profile" ) - request.setProfileName( value ); - else if ( key == "hostname" ) - request.setHeloHostname( value ); - else if ( key == "body" ) - request.set8BitBody( value.upper() == "8BIT" ); - else if ( key == "size" ) - request.setSize( value.toUInt() ); - else - kdWarning(7112) << "while parsing query: unknown query item \"" - << key << "\" with value \"" << value << "\"" << endl; - } - - return request; - } - - TQCString Request::heloHostnameCString() const { - return KIDNA::toAsciiCString( heloHostname() ); - } - - static bool isUsAscii( const TQString & s ) { - for ( uint i = 0 ; i < s.length() ; ++i ) - if ( s[i].unicode() > 127 ) return false; - return true; - } - - - - static inline bool isSpecial( char ch ) { - static const TQCString specials = "()<>[]:;@\\,.\""; - return specials.find( ch ) >= 0; - } - - - - static inline bool needsQuoting( char ch ) { - return ch == '\\' || ch == '"' || ch == '\n' ; - } - - - - static inline TQCString rfc2047Encode( const TQString & s ) { - TQCString r = KCodecs::base64Encode( s.stripWhiteSpace().utf8(), false ); - return "=?utf-8?b?" + r + "?=" ; // use base64 since that always gives a valid encoded-word - } - - - - static TQCString quote( const TQString & s ) { - assert( isUsAscii( s ) ); - - TQCString r( s.length() * 2 ); - bool needsQuotes = false; - - unsigned int j = 0; - for ( unsigned int i = 0 ; i < s.length() ; ++i ) { - char ch = s[i].latin1(); - if ( isSpecial( ch ) ) { - if ( needsQuoting( ch ) ) - r[j++] = '\\'; - needsQuotes = true; - } - r[j++] = ch; - } - r.truncate( j ); - - if ( needsQuotes ) - return '"' + r + '"'; - else - return r; - } - - - - static TQCString formatFromAddress( const TQString & fromRealName, const TQString & fromAddress ) { - if ( fromRealName.isEmpty() ) - return fromAddress.latin1(); // no real name: return "joe@user.org" - - // return "Joe User <joe@user.org>", "\"User, Joe\" <joe@user.org>" - // or "=?utf-8?q?Joe_User?= <joe@user.org>", depending on real name's nature. - TQCString r = isUsAscii( fromRealName ) ? quote( fromRealName ) : rfc2047Encode( fromRealName ); - return r + " <" + fromAddress.latin1() + '>'; - } - - - - static TQCString formatSubject( TQString s ) { - if ( isUsAscii( s ) ) - return TQString(s.remove( '\n' )).latin1(); // don't break header folding, - // so remove any line break - // that happen to be around - else - return rfc2047Encode( s ); - } - - - - TQCString Request::headerFields( const TQString & fromRealName ) const { - if ( !emitHeaders() ) - return 0; - - assert( hasFromAddress() ); // should have been checked for by - // caller (MAIL FROM comes before DATA) - - TQCString result = "From: " + formatFromAddress( fromRealName, fromAddress() ) + "\r\n"; - - if ( !subject().isEmpty() ) - result += "Subject: " + formatSubject( subject() ) + "\r\n"; - if ( !to().empty() ) - result += TQCString( "To: " ) + to().join( ",\r\n\t" /* line folding */ ).latin1() + "\r\n"; - if ( !cc().empty() ) - result += TQCString( "Cc: " ) + cc().join( ",\r\n\t" /* line folding */ ).latin1() + "\r\n"; - return result; - } - -} // namespace KioSMTP diff --git a/kioslave/smtp/request.h b/kioslave/smtp/request.h deleted file mode 100644 index e1b3acda8..000000000 --- a/kioslave/smtp/request.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- c++ -*- - request.h - - This file is part of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2003 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#ifndef __KIOSMTP_REQUEST_H__ -#define __KIOSMTP_REQUEST_H__ - -#include <tqstring.h> -#include <tqstringlist.h> - -class KURL; - -namespace KioSMTP { - - class Request { - public: - Request() - : mSubject( "missing subject" ), mEmitHeaders( true ), - m8Bit( false ), mSize( 0 ) {} - - static Request fromURL( const KURL & url ); - - TQString profileName() const { return mProfileName; } - void setProfileName( const TQString & profileName ) { mProfileName = profileName; } - bool hasProfile() const { return !profileName().isNull(); } - - TQString subject() const { return mSubject; } - void setSubject( const TQString & subject ) { mSubject = subject; } - - TQString fromAddress() const { return mFromAddress; } - void setFromAddress( const TQString & fromAddress ) { mFromAddress = fromAddress; } - bool hasFromAddress() const { return !mFromAddress.isEmpty(); } - - TQStringList recipients() const { return to() + cc() + bcc() ; } - bool hasRecipients() const { return !to().empty() || !cc().empty() || !bcc().empty() ; } - - TQStringList to() const { return mTo; } - TQStringList cc() const { return mCc; } - TQStringList bcc() const { return mBcc; } - void addTo( const TQString & to ) { mTo.push_back( to ); } - void addCc( const TQString & cc ) { mCc.push_back( cc ); } - void addBcc( const TQString & bcc ) { mBcc.push_back( bcc ); } - - TQString heloHostname() const { return mHeloHostname; } - TQCString heloHostnameCString() const; - void setHeloHostname( const TQString & hostname ) { mHeloHostname = hostname; } - - bool emitHeaders() const { return mEmitHeaders; } - void setEmitHeaders( bool emitHeaders ) { mEmitHeaders = emitHeaders; } - - bool is8BitBody() const { return m8Bit; } - void set8BitBody( bool a8Bit ) { m8Bit = a8Bit; } - - unsigned int size() const { return mSize; } - void setSize( unsigned int size ) { mSize = size; } - - /** If @ref #emitHeaders() is true, returns the rfc2822 - serialization of the header fields "To", "Cc", "Subject" and - "From", as determined by the respective settings. If @ref - #emitHeaders() is false, returns a null string. */ - TQCString headerFields( const TQString & fromRealName=TQString::null ) const; - - private: - TQStringList mTo, mCc, mBcc; - TQString mProfileName, mSubject, mFromAddress, mHeloHostname; - bool mEmitHeaders; - bool m8Bit; - unsigned int mSize; - }; - -} // namespace KioSMTP - -#endif // __KIOSMTP_REQUEST_H__ diff --git a/kioslave/smtp/response.cc b/kioslave/smtp/response.cc deleted file mode 100644 index 0ddce0e5a..000000000 --- a/kioslave/smtp/response.cc +++ /dev/null @@ -1,160 +0,0 @@ -/* -*- c++ -*- - response.cc - - This file is part of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2003 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#include <config.h> - -#include "response.h" - -#include <klocale.h> -#include <kio/global.h> - -#include <tqstring.h> - -namespace KioSMTP { - - void Response::parseLine( const char * line, int len ) { - - if ( !isWellFormed() ) return; // don't bother - - if ( isComplete() ) - // if the response is already complete, there can't be another line - mValid = false; - - if ( len > 1 && line[len-1] == '\n' && line[len-2] == '\r' ) - len -= 2; - - if ( len < 3 ) { - // can't be valid - too short - mValid = false; - mWellFormed = false; - return; - } - - bool ok = false; - unsigned int code = TQCString( line, 3+1 ).toUInt( &ok ); - if ( !ok || code < 100 || code > 559 ) { - // not a number or number out of range - mValid = false; - if ( !ok || code < 100 ) - mWellFormed = false; - return; - } - if ( mCode && code != mCode ) { - // different codes in one response are not allowed. - mValid = false; - return; - } - mCode = code; - - if ( len == 3 || line[3] == ' ' ) - mSawLastLine = true; - else if ( line[3] != '-' ) { - // code must be followed by either SP or hyphen (len == 3 is - // also accepted since broken servers exist); all else is - // invalid - mValid = false; - mWellFormed = false; - return; - } - - mLines.push_back( len > 4 ? TQCString( line+4, len-4+1 ).stripWhiteSpace() : TQCString() ); - } - - - // hackishly fixing QCStringList flaws... - static TQCString join( char sep, const QCStringList & list ) { - if ( list.empty() ) - return TQCString(); - TQCString result = list.front(); - for ( QCStringList::const_iterator it = ++list.begin() ; it != list.end() ; ++it ) - result += sep + *it; - return result; - } - - TQString Response::errorMessage() const { - TQString msg; - if ( lines().count() > 1 ) - msg = i18n("The server responded:\n%1") - .arg( static_cast<const char *>(join( '\n', lines()) ) ); - else - msg = i18n("The server responded: \"%1\"") - .arg( static_cast<const char *>(lines().front()) ); - if ( first() == 4 ) - msg += '\n' + i18n("This is a temporary failure. " - "You may try again later."); - return msg; - } - - int Response::errorCode() const { - switch ( code() ) { - case 421: // Service not available, closing transmission channel - case 454: // TLS not available due to temporary reason - // Temporary authentication failure - case 554: // Transaction failed / No SMTP service here / No valid recipients - return TDEIO::ERR_SERVICE_NOT_AVAILABLE; - - case 451: // Requested action aborted: local error in processing - return TDEIO::ERR_INTERNAL_SERVER; - - case 452: // Requested action not taken: insufficient system storage - case 552: // Requested mail action aborted: exceeded storage allocation - return TDEIO::ERR_DISK_FULL; - - case 500: // Syntax error, command unrecognized - case 501: // Syntax error in parameters or arguments - case 502: // Command not implemented - case 503: // Bad sequence of commands - case 504: // Command parameter not implemented - return TDEIO::ERR_INTERNAL; - - case 450: // Requested mail action not taken: mailbox unavailable - case 550: // Requested action not taken: mailbox unavailable - case 551: // User not local; please try <forward-path> - case 553: // Requested action not taken: mailbox name not allowed - return TDEIO::ERR_DOES_NOT_EXIST; - - case 530: // {STARTTLS,Authentication} required - case 538: // Encryption required for requested authentication mechanism - case 534: // Authentication mechanism is too weak - return TDEIO::ERR_UPGRADE_REQUIRED; - - case 432: // A password transition is needed - return TDEIO::ERR_COULD_NOT_AUTHENTICATE; - - default: - if ( isPositive() ) - return 0; - else - return TDEIO::ERR_UNKNOWN; - } - } - -} // namespace KioSMTP diff --git a/kioslave/smtp/response.h b/kioslave/smtp/response.h deleted file mode 100644 index 2fd48ebf3..000000000 --- a/kioslave/smtp/response.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -*- c++ -*- - response.h - - This file is part of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2003 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#ifndef __KIOSMTP_RESPONSE_H__ -#define __KIOSMTP_RESPONSE_H__ - -#include <tqcstring.h> -#include <tqvaluelist.h> -typedef TQValueList<TQCString> QCStringList; - -class TQString; - -namespace KioSMTP { - - class Response { - public: - Response() - : mCode(0), - mValid(true), - mSawLastLine(false), - mWellFormed(true) {} - - void parseLine( const char * line ) { - parseLine( line, tqstrlen( line ) ); - } - void parseLine( const char * line, int len ); - - /** Return an internationalized error message according to the - response's code. */ - TQString errorMessage() const; - /** Translate the SMTP error code into a KIO one */ - int errorCode() const; - - enum Reply { - UnknownReply = -1, - PositivePreliminary = 1, - PositiveCompletion = 2, - PositiveIntermediate = 3, - TransientNegative = 4, - PermanentNegative = 5 - }; - - enum Category { - UnknownCategory = -1, - SyntaxError = 0, - Information = 1, - Connections = 2, - MailSystem = 5 - }; - - unsigned int code() const { return mCode; } - unsigned int first() const { return code() / 100 ; } - unsigned int second() const { return ( code() % 100 ) / 10 ; } - unsigned int third() const { return code() % 10 ; } - - bool isPositive() const { return first() <= 3 && first() >= 1 ; } - bool isNegative() const { return first() == 4 || first() == 5 ; } - bool isUnknown() const { return !isPositive() && !isNegative() ; } - - QCStringList lines() const { return mLines; } - - bool isValid() const { return mValid; } - bool isComplete() const { return mSawLastLine; } - - /** Shortcut method. - @return true iff the response is valid, complete and positive */ - bool isOk() const { return isValid() && isComplete() && isPositive() ; } - /** Indicates whether the response was well-formed, meaning it - obeyed the syntax of smtp responses. That the response - nevertheless is not valid may be caused by e.g. different - response codes in a multilie response. A non-well-formed - response is never valid. */ - bool isWellFormed() const { return mWellFormed; } - - void clear() { *this = Response(); } - -#ifdef KIOSMTP_COMPARATORS - bool operator==( const Response & other ) const { - return mCode == other.mCode && - mValid == other.mValid && - mSawLastLine == other.mSawLastLine && - mWellFormed == other.mWellFormed && - mLines == other.mLines; - } -#endif - - private: - unsigned int mCode; - QCStringList mLines; - bool mValid; - bool mSawLastLine; - bool mWellFormed; - }; - -} // namespace KioSMTP - -#endif // __KIOSMTP_RESPONSE_H__ diff --git a/kioslave/smtp/smtp.cc b/kioslave/smtp/smtp.cc deleted file mode 100644 index b1effa415..000000000 --- a/kioslave/smtp/smtp.cc +++ /dev/null @@ -1,647 +0,0 @@ -/* - * Copyright (c) 2000, 2001 Alex Zepeda <zipzippy@sonic.net> - * Copyright (c) 2001 Michael Häckel <Michael@Haeckel.Net> - * Copyright (c) 2002 Aaron J. Seigo <aseigo@olympusproject.org> - * Copyright (c) 2003 Marc Mutz <mutz@kde.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#include <config.h> - -#ifdef HAVE_LIBSASL2 -extern "C" { -#include <sasl/sasl.h> -} -#endif - -#include "smtp.h" -#include "request.h" -#include "response.h" -#include "transactionstate.h" -#include "command.h" -using KioSMTP::Capabilities; -using KioSMTP::Command; -using KioSMTP::EHLOCommand; -using KioSMTP::AuthCommand; -using KioSMTP::MailFromCommand; -using KioSMTP::RcptToCommand; -using KioSMTP::DataCommand; -using KioSMTP::TransferCommand; -using KioSMTP::Request; -using KioSMTP::Response; -using KioSMTP::TransactionState; - -#include <kemailsettings.h> -#include <ksock.h> -#include <kdebug.h> -#include <kinstance.h> -#include <kio/connection.h> -#include <kio/slaveinterface.h> -#include <klocale.h> - -#include <tqstring.h> -#include <tqstringlist.h> -#include <tqcstring.h> - -#include <memory> -using std::auto_ptr; - -#include <ctype.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <assert.h> - -#ifdef HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif -#ifdef HAVE_SYS_SOCKET_H -# include <sys/socket.h> -#endif -#include <netdb.h> - -#ifndef NI_NAMEREQD -// FIXME for KDE 3.3: fake defintion -// API design flaw in KExtendedSocket::resolve -# define NI_NAMEREQD 0 -#endif - - -extern "C" { - KDE_EXPORT int kdemain(int argc, char **argv); -} - -int kdemain(int argc, char **argv) -{ - TDEInstance instance("kio_smtp"); - - if (argc != 4) { - fprintf(stderr, - "Usage: kio_smtp protocol domain-socket1 domain-socket2\n"); - exit(-1); - } - -#ifdef HAVE_LIBSASL2 - if ( sasl_client_init( NULL ) != SASL_OK ) { - fprintf(stderr, "SASL library initialization failed!\n"); - exit(-1); - } -#endif - SMTPProtocol slave( argv[2], argv[3], tqstricmp( argv[1], "smtps" ) == 0 ); - slave.dispatchLoop(); -#ifdef HAVE_LIBSASL2 - sasl_done(); -#endif - return 0; -} - -SMTPProtocol::SMTPProtocol(const TQCString & pool, const TQCString & app, - bool useSSL) -: TCPSlaveBase(useSSL ? 465 : 25, - useSSL ? "smtps" : "smtp", - pool, app, useSSL), - m_iOldPort(0), - m_opened(false) -{ - //kdDebug(7112) << "SMTPProtocol::SMTPProtocol" << endl; - mPendingCommandQueue.setAutoDelete( true ); - mSentCommandQueue.setAutoDelete( true ); -} - -unsigned int SMTPProtocol::sendBufferSize() const { - // ### how much is eaten by SSL/TLS overhead? - const int fd = fileno( fp ); - int value = -1; - kde_socklen_t len = sizeof(value); - if ( fd < 0 || ::getsockopt( fd, SOL_SOCKET, SO_SNDBUF, (char*)&value, &len ) ) - value = 1024; // let's be conservative - kdDebug(7112) << "send buffer size seems to be " << value << " octets." << endl; - return value > 0 ? value : 1024 ; -} - -SMTPProtocol::~SMTPProtocol() { - //kdDebug(7112) << "SMTPProtocol::~SMTPProtocol" << endl; - smtp_close(); -} - -void SMTPProtocol::openConnection() { - if ( smtp_open() ) - connected(); - else - closeConnection(); -} - -void SMTPProtocol::closeConnection() { - smtp_close(); -} - -void SMTPProtocol::special( const TQByteArray & aData ) { - TQDataStream s( aData, IO_ReadOnly ); - int what; - s >> what; - if ( what == 'c' ) { - infoMessage( createSpecialResponse() ); -#ifndef NDEBUG - kdDebug(7112) << "special('c') returns \"" << createSpecialResponse() << "\"" << endl; -#endif - } else if ( what == 'N' ) { - if ( !execute( Command::NOOP ) ) - return; - } else { - error( TDEIO::ERR_INTERNAL, - i18n("The application sent an invalid request.") ); - return; - } - finished(); -} - - -// Usage: smtp://smtphost:port/send?to=user@host.com&subject=blah -// If smtphost is the name of a profile, it'll use the information -// provided by that profile. If it's not a profile name, it'll use it as -// nature intended. -// One can also specify in the query: -// headers=0 (turns off header generation) -// to=emailaddress -// cc=emailaddress -// bcc=emailaddress -// subject=text -// profile=text (this will override the "host" setting) -// hostname=text (used in the HELO) -// body={7bit,8bit} (default: 7bit; 8bit activates the use of the 8BITMIME SMTP extension) -void SMTPProtocol::put(const KURL & url, int /*permissions */ , - bool /*overwrite */ , bool /*resume */ ) -{ - Request request = Request::fromURL( url ); // parse settings from URL's query - - KEMailSettings mset; - KURL open_url = url; - if ( !request.hasProfile() ) { - //kdDebug(7112) << "kio_smtp: Profile is null" << endl; - bool hasProfile = mset.profiles().contains( open_url.host() ); - if ( hasProfile ) { - mset.setProfile(open_url.host()); - open_url.setHost(mset.getSetting(KEMailSettings::OutServer)); - m_sUser = mset.getSetting(KEMailSettings::OutServerLogin); - m_sPass = mset.getSetting(KEMailSettings::OutServerPass); - - if (m_sUser.isEmpty()) - m_sUser = TQString::null; - if (m_sPass.isEmpty()) - m_sPass = TQString::null; - open_url.setUser(m_sUser); - open_url.setPass(m_sPass); - m_sServer = open_url.host(); - m_iPort = open_url.port(); - } - else { - mset.setProfile(mset.defaultProfileName()); - } - } - else { - mset.setProfile( request.profileName() ); - } - - // Check KEMailSettings to see if we've specified an E-Mail address - // if that worked, check to see if we've specified a real name - // and then format accordingly (either: emailaddress@host.com or - // Real Name <emailaddress@host.com>) - if ( !request.hasFromAddress() ) { - const TQString from = mset.getSetting( KEMailSettings::EmailAddress ); - if ( !from.isNull() ) - request.setFromAddress( from ); - else if ( request.emitHeaders() ) { - error(TDEIO::ERR_NO_CONTENT, i18n("The sender address is missing.")); - return; - } - } - - if ( !smtp_open( request.heloHostname() ) ) - { - error(TDEIO::ERR_SERVICE_NOT_AVAILABLE, - i18n("SMTPProtocol::smtp_open failed (%1)") // ### better error message? - .arg(open_url.path())); - return; - } - - if ( request.is8BitBody() - && !haveCapability("8BITMIME") && metaData("8bitmime") != "on" ) { - error( TDEIO::ERR_SERVICE_NOT_AVAILABLE, - i18n("Your server does not support sending of 8-bit messages.\n" - "Please use base64 or quoted-printable encoding.") ); - return; - } - - queueCommand( new MailFromCommand( this, request.fromAddress().latin1(), - request.is8BitBody(), request.size() ) ); - - // Loop through our To and CC recipients, and send the proper - // SMTP commands, for the benefit of the server. - TQStringList recipients = request.recipients(); - for ( TQStringList::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it ) - queueCommand( new RcptToCommand( this, (*it).latin1() ) ); - - queueCommand( Command::DATA ); - queueCommand( new TransferCommand( this, request.headerFields( mset.getSetting( KEMailSettings::RealName ) ) ) ); - - TransactionState ts; - if ( !executeQueuedCommands( &ts ) ) { - if ( ts.errorCode() ) - error( ts.errorCode(), ts.errorMessage() ); - } else - finished(); -} - - -void SMTPProtocol::setHost(const TQString & host, int port, - const TQString & user, const TQString & pass) -{ - m_sServer = host; - m_iPort = port; - m_sUser = user; - m_sPass = pass; -} - -bool SMTPProtocol::sendCommandLine( const TQCString & cmdline ) { - //kdDebug( cmdline.length() < 4096, 7112) << "C: " << cmdline.data(); - //kdDebug( cmdline.length() >= 4096, 7112) << "C: <" << cmdline.length() << " bytes>" << endl; - kdDebug( 7112) << "C: <" << cmdline.length() << " bytes>" << endl; - ssize_t cmdline_len = cmdline.length(); - if ( write( cmdline.data(), cmdline_len ) != cmdline_len ) { - error( TDEIO::ERR_COULD_NOT_WRITE, m_sServer ); - return false; - } - return true; -} - -Response SMTPProtocol::getResponse( bool * ok ) { - - if ( ok ) - *ok = false; - - Response response; - char buf[2048]; - - int recv_len = 0; - do { - // wait for data... - if ( !waitForResponse( 600 ) ) { - error( TDEIO::ERR_SERVER_TIMEOUT, m_sServer ); - return response; - } - - // ...read data... - recv_len = readLine( buf, sizeof(buf) - 1 ); - if ( recv_len < 1 && !isConnectionValid() ) { - error( TDEIO::ERR_CONNECTION_BROKEN, m_sServer ); - return response; - } - - kdDebug(7112) << "S: " << TQCString( buf, recv_len + 1 ).data(); - // ...and parse lines... - response.parseLine( buf, recv_len ); - - // ...until the response is complete or the parser is so confused - // that it doesn't think a RSET would help anymore: - } while ( !response.isComplete() && response.isWellFormed() ); - - if ( !response.isValid() ) { - error( TDEIO::ERR_NO_CONTENT, i18n("Invalid SMTP response (%1) received.").arg(response.code()) ); - return response; - } - - if ( ok ) - *ok = true; - - return response; -} - -bool SMTPProtocol::executeQueuedCommands( TransactionState * ts ) { - assert( ts ); - - kdDebug( canPipelineCommands(), 7112 ) << "using pipelining" << endl; - - while( !mPendingCommandQueue.isEmpty() ) { - TQCString cmdline = collectPipelineCommands( ts ); - if ( ts->failedFatally() ) { - smtp_close( false ); // _hard_ shutdown - return false; - } - if ( ts->failed() ) - break; - if ( cmdline.isEmpty() ) - continue; - if ( !sendCommandLine( cmdline ) || - !batchProcessResponses( ts ) || - ts->failedFatally() ) { - smtp_close( false ); // _hard_ shutdown - return false; - } - } - - if ( ts->failed() ) { - if ( !execute( Command::RSET ) ) - smtp_close( false ); - return false; - } - return true; -} - -TQCString SMTPProtocol::collectPipelineCommands( TransactionState * ts ) { - assert( ts ); - - TQCString cmdLine; - unsigned int cmdLine_len = 0; - - while ( mPendingCommandQueue.head() ) { - - Command * cmd = mPendingCommandQueue.head(); - - if ( cmd->doNotExecute( ts ) ) { - delete mPendingCommandQueue.dequeue(); - if ( cmdLine_len ) - break; - else - continue; - } - - if ( cmdLine_len && cmd->mustBeFirstInPipeline() ) - break; - - if ( cmdLine_len && !canPipelineCommands() ) - break; - - while ( !cmd->isComplete() && !cmd->needsResponse() ) { - const TQCString currentCmdLine = cmd->nextCommandLine( ts ); - if ( ts->failedFatally() ) - return cmdLine; - const unsigned int currentCmdLine_len = currentCmdLine.length(); - - if ( cmdLine_len && cmdLine_len + currentCmdLine_len > sendBufferSize() ) { - // must all fit into the send buffer, else connection deadlocks, - // but we need to have at least _one_ command to send - cmd->ungetCommandLine( currentCmdLine, ts ); - return cmdLine; - } - cmdLine_len += currentCmdLine_len; - cmdLine += currentCmdLine; - } - - mSentCommandQueue.enqueue( mPendingCommandQueue.dequeue() ); - - if ( cmd->mustBeLastInPipeline() ) - break; - } - - return cmdLine; -} - -bool SMTPProtocol::batchProcessResponses( TransactionState * ts ) { - assert( ts ); - - while ( !mSentCommandQueue.isEmpty() ) { - - Command * cmd = mSentCommandQueue.head(); - assert( cmd->isComplete() ); - - bool ok = false; - Response r = getResponse( &ok ); - if ( !ok ) - return false; - cmd->processResponse( r, ts ); - if ( ts->failedFatally() ) - return false; - - mSentCommandQueue.remove(); - } - - return true; -} - -void SMTPProtocol::queueCommand( int type ) { - queueCommand( Command::createSimpleCommand( type, this ) ); -} - -bool SMTPProtocol::execute( int type, TransactionState * ts ) { - auto_ptr<Command> cmd( Command::createSimpleCommand( type, this ) ); - kdFatal( !cmd.get(), 7112 ) << "Command::createSimpleCommand( " << type << " ) returned null!" << endl; - return execute( cmd.get(), ts ); -} - -// ### fold into pipelining engine? How? (execute() is often called -// ### when command queues are _not_ empty!) -bool SMTPProtocol::execute( Command * cmd, TransactionState * ts ) -{ - kdFatal( !cmd, 7112 ) << "SMTPProtocol::execute() called with no command to run!" << endl; - - if (!cmd) - return false; - - if ( cmd->doNotExecute( ts ) ) - return true; - - do { - while ( !cmd->isComplete() && !cmd->needsResponse() ) { - const TQCString cmdLine = cmd->nextCommandLine( ts ); - if ( ts && ts->failedFatally() ) { - smtp_close( false ); - return false; - } - if ( cmdLine.isEmpty() ) - continue; - if ( !sendCommandLine( cmdLine ) ) { - smtp_close( false ); - return false; - } - } - - bool ok = false; - Response r = getResponse( &ok ); - if ( !ok ) { - smtp_close( false ); - return false; - } - if ( !cmd->processResponse( r, ts ) ) { - if ( ts && ts->failedFatally() || - cmd->closeConnectionOnError() || - !execute( Command::RSET ) ) - smtp_close( false ); - return false; - } - } while ( !cmd->isComplete() ); - - return true; -} - -bool SMTPProtocol::smtp_open(const TQString& fakeHostname) -{ - if (m_opened && - m_iOldPort == port(m_iPort) && - m_sOldServer == m_sServer && - m_sOldUser == m_sUser && - (fakeHostname.isNull() || m_hostname == fakeHostname)) - return true; - - smtp_close(); - if (!connectToHost(m_sServer, m_iPort)) - return false; // connectToHost has already send an error message. - m_opened = true; - - bool ok = false; - Response greeting = getResponse( &ok ); - if ( !ok || !greeting.isOk() ) - { - if ( ok ) - error( TDEIO::ERR_COULD_NOT_LOGIN, - i18n("The server did not accept the connection.\n" - "%1").arg( greeting.errorMessage() ) ); - smtp_close(); - return false; - } - - if (!fakeHostname.isNull()) - { - m_hostname = fakeHostname; - } - else - { - TQString tmpPort; - TDESocketAddress* addr = KExtendedSocket::localAddress(m_iSock); - // perform name lookup. NI_NAMEREQD means: don't return a numeric - // value (we need to know when we get have the IP address, so we - // can enclose it in sqaure brackets (domain-literal). Failure to - // do so is normally harmless with IPv4, but fails for IPv6: - if (KExtendedSocket::resolve(addr, m_hostname, tmpPort, NI_NAMEREQD) != 0) - // FQDN resolution failed - // use the IP address as domain-literal - m_hostname = '[' + addr->nodeName() + ']'; - delete addr; - - if(m_hostname.isEmpty()) - { - m_hostname = "localhost.invalid"; - } - } - - EHLOCommand ehloCmdPreTLS( this, m_hostname ); - if ( !execute( &ehloCmdPreTLS ) ) { - smtp_close(); - return false; - } - - if ( ( haveCapability("STARTTLS") && canUseTLS() && metaData("tls") != "off" ) - || metaData("tls") == "on" ) { - // For now we're gonna force it on. - - if ( execute( Command::STARTTLS ) ) { - - // re-issue EHLO to refresh the capability list (could be have - // been faked before TLS was enabled): - EHLOCommand ehloCmdPostTLS( this, m_hostname ); - if ( !execute( &ehloCmdPostTLS ) ) { - smtp_close(); - return false; - } - } - } - // Now we try and login - if (!authenticate()) { - smtp_close(); - return false; - } - - m_iOldPort = m_iPort; - m_sOldServer = m_sServer; - m_sOldUser = m_sUser; - m_sOldPass = m_sPass; - - return true; -} - -bool SMTPProtocol::authenticate() -{ - // return with success if the server doesn't support SMTP-AUTH or an user - // name is not specified and metadata doesn't tell us to force it. - if ( (m_sUser.isEmpty() || !haveCapability( "AUTH" )) && - metaData( "sasl" ).isEmpty() ) return true; - - TDEIO::AuthInfo authInfo; - authInfo.username = m_sUser; - authInfo.password = m_sPass; - authInfo.prompt = i18n("Username and password for your SMTP account:"); - - TQStringList strList; - - if (!metaData("sasl").isEmpty()) - strList.append(metaData("sasl").latin1()); - else - strList = mCapabilities.saslMethodsQSL(); - - AuthCommand authCmd( this, strList.join(" ").latin1(), m_sServer, authInfo ); - bool ret = execute( &authCmd ); - m_sUser = authInfo.username; - m_sPass = authInfo.password; - return ret; -} - -void SMTPProtocol::parseFeatures( const Response & ehloResponse ) { - mCapabilities = Capabilities::fromResponse( ehloResponse ); - - TQString category = usingTLS() ? "TLS" : usingSSL() ? "SSL" : "PLAIN" ; - setMetaData( category + " AUTH METHODS", mCapabilities.authMethodMetaData() ); - setMetaData( category + " CAPABILITIES", mCapabilities.asMetaDataString() ); -#ifndef NDEBUG - kdDebug(7112) << "parseFeatures() " << category << " AUTH METHODS:" - << '\n' + mCapabilities.authMethodMetaData() << endl - << "parseFeatures() " << category << " CAPABILITIES:" - << '\n' + mCapabilities.asMetaDataString() << endl; -#endif -} - -void SMTPProtocol::smtp_close( bool nice ) { - if (!m_opened) // We're already closed - return; - - if ( nice ) - execute( Command::QUIT ); - kdDebug( 7112 ) << "closing connection" << endl; - closeDescriptor(); - m_sOldServer = TQString::null; - m_sOldUser = TQString::null; - m_sOldPass = TQString::null; - - mCapabilities.clear(); - mPendingCommandQueue.clear(); - mSentCommandQueue.clear(); - - m_opened = false; -} - -void SMTPProtocol::stat(const KURL & url) -{ - TQString path = url.path(); - error(TDEIO::ERR_DOES_NOT_EXIST, url.path()); -} - diff --git a/kioslave/smtp/smtp.h b/kioslave/smtp/smtp.h deleted file mode 100644 index eef1aab42..000000000 --- a/kioslave/smtp/smtp.h +++ /dev/null @@ -1,148 +0,0 @@ -/* -*- c++ -*- - * Copyright (c) 2000, 2001 Alex Zepeda <zipzippy@sonic.net> - * Copyright (c) 2001 Michael H�ckel <Michael@Haeckel.Net> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifndef _SMTP_H -#define _SMTP_H - -#include <kio/tcpslavebase.h> - -#include "capabilities.h" - -#include <tqstring.h> -#include <tqptrqueue.h> - -class KURL; -class TQCString; -template <typename T> class TQMemArray; -#ifdef USE_QT3 -typedef TQMemArray<char> TQByteArray; -#endif // USE_QT3 - -namespace KioSMTP { - class Response; - class TransactionState; - class Command; -} - -class SMTPProtocol : public TDEIO::TCPSlaveBase { - friend class KioSMTP::Command; -public: - SMTPProtocol(const TQCString & pool, const TQCString & app, bool useSSL); - virtual ~ SMTPProtocol(); - - virtual void setHost(const TQString & host, int port, - const TQString & user, const TQString & pass); - - virtual void special(const TQByteArray & aData); - virtual void put(const KURL & url, int permissions, bool overwrite, - bool resume); - virtual void stat(const KURL & url); - virtual void openConnection(); - virtual void closeConnection(); - -protected: - - bool smtp_open(const TQString& fakeHostname = TQString::null); - - /** Closes the connection. If @p nice is true (default), then QUIT - is sent and it's reponse waited for. */ - void smtp_close( bool nice=true ); - - /** Execute command @p cmd */ - bool execute( KioSMTP::Command * cmd, KioSMTP::TransactionState * ts=0 ); - /** Execute a command of type @p type */ - bool execute( int type, KioSMTP::TransactionState * ts=0 ); - /** Execute the queued commands. If something goes horribly wrong - (sending command oline fails, getting response fails or some - command raises the failedFatally() flag in @p ts, shuts down the - connection with <code>smtp_close( false )</code>. If The - transaction fails gracefully (<code>ts->failed()</code> is - true), issues a RSET command. - - @return true if transaction succeeded, false otherwise. - **/ - bool executeQueuedCommands( KioSMTP::TransactionState * ts ); - - /** Parse a single response from the server. Single- vs. multiline - responses are correctly detected. - - @param ok if not 0, returns whether response parsing was - successful. Don't confuse this with negative responses - (e.g. 5xx), which you can check for using - @ref Response::isNegative() - @return the @ref Response object representing the server response. - **/ - KioSMTP::Response getResponse( bool * ok ); - - bool authenticate(); - void parseFeatures( const KioSMTP::Response & ehloResponse ); - - bool sendCommandLine( const TQCString & cmd ); - TQCString collectPipelineCommands( KioSMTP::TransactionState * ts ); - bool batchProcessResponses( KioSMTP::TransactionState * ts ); - - /** This is a pure convenience wrapper around - @ref KioSMTP::Capabilities::have() */ - bool haveCapability( const char * cap ) const { - return mCapabilities.have( cap ); - } - - /** @return true is pipelining is available and allowed by metadata */ - bool canPipelineCommands() const { - return haveCapability("PIPELINING") && metaData("pipelining") != "off" ; - } - - /** Wrapper around getsockopt(..., SO_SNDBUF,...) */ - unsigned int sendBufferSize() const; - - /** This is a pure convenience wrapper around - @ref KioSMTP::Capabilities::createSpecialResponse */ - TQString createSpecialResponse() const { - return mCapabilities.createSpecialResponse( usingTLS() || haveCapability( "STARTTLS" ) ); - } - - void queueCommand( KioSMTP::Command * command ) { - mPendingCommandQueue.enqueue( command ); - } - void queueCommand( int type ); - - unsigned short m_iOldPort; - bool m_opened; - TQString m_sServer, m_sOldServer; - TQString m_sUser, m_sOldUser; - TQString m_sPass, m_sOldPass; - TQString m_hostname; - - KioSMTP::Capabilities mCapabilities; - - typedef TQPtrQueue<KioSMTP::Command> CommandQueue; - CommandQueue mPendingCommandQueue; - CommandQueue mSentCommandQueue; -}; - -#endif // _SMTP_H diff --git a/kioslave/smtp/smtp.protocol b/kioslave/smtp/smtp.protocol deleted file mode 100644 index e01be9c7f..000000000 --- a/kioslave/smtp/smtp.protocol +++ /dev/null @@ -1,16 +0,0 @@ -[Protocol] -exec=kio_smtp -protocol=smtp -Capabilities=SASL -input=none -output=filesystem -listing=Name,Type,Size -reading=false -writing=true -deleting=false -source=true -makedir=false -linking=false -moving=false -DocPath=kioslave/smtp.html -Icon=folder_outbox diff --git a/kioslave/smtp/smtps.protocol b/kioslave/smtp/smtps.protocol deleted file mode 100644 index 2087845f2..000000000 --- a/kioslave/smtp/smtps.protocol +++ /dev/null @@ -1,15 +0,0 @@ -[Protocol] -exec=kio_smtp -protocol=smtps -Capabilities=SASL -input=none -output=filesystem -listing=Name,Type,Size -reading=false -writing=true -deleting=false -source=true -makedir=false -linking=false -moving=false -Icon=folder_outbox diff --git a/kioslave/smtp/test_commands.cc b/kioslave/smtp/test_commands.cc deleted file mode 100644 index 458b386b8..000000000 --- a/kioslave/smtp/test_commands.cc +++ /dev/null @@ -1,728 +0,0 @@ -#include <kio/global.h> -#include <kdebug.h> - -#include <tqstring.h> -#include <tqcstring.h> -#include <tqstringlist.h> - -//#include <iostream> -//using std::cout; -//using std::endl; - -namespace KioSMTP { - class Response; -}; - -// fake -class SMTPProtocol { -public: - SMTPProtocol() { clear(); } - - // - // public members to control the API emulation below: - // - int startTLSReturnCode; - bool usesSSL; - bool usesTLS; - int lastErrorCode; - TQString lastErrorMessage; - int lastMessageBoxCode; - TQString lastMessageBoxText; - TQByteArray nextData; - int nextDataReturnCode; - TQStringList caps; - TDEIO::MetaData metadata; - - void clear() { - startTLSReturnCode = 1; - usesSSL = usesTLS = false; - lastErrorCode = lastMessageBoxCode = 0; - lastErrorMessage = lastMessageBoxText = TQString::null; - nextData.resize( 0 ); - nextDataReturnCode = -1; - caps.clear(); - metadata.clear(); - } - - // - // emulated API: - // - void parseFeatures( const KioSMTP::Response & ) { /* noop */ } - int startTLS() { - if ( startTLSReturnCode == 1 ) - usesTLS = true; - return startTLSReturnCode; - } - bool usingSSL() const { return usesSSL; } - bool usingTLS() const { return usesTLS; } - bool haveCapability( const char * cap ) const { return caps.contains( cap ); } - void error( int id, const TQString & msg ) { - lastErrorCode = id; - lastErrorMessage = msg; - } - void messageBox( int id, const TQString & msg, const TQString & ) { - lastMessageBoxCode = id; - lastMessageBoxText = msg; - } - void dataReq() { /* noop */ } - int readData( TQByteArray & ba ) { ba = nextData; return nextDataReturnCode; } - TQString metaData( const TQString & key ) const { return metadata[key]; } - -}; - -#define _SMTP_H - -#define KIOSMTP_COMPARATORS // for TransactionState::operator== -#include "command.h" -#include "response.h" -#include "transactionstate.h" - -#include <assert.h> - -using namespace KioSMTP; - -static const char * foobarbaz = ".Foo bar baz"; -static const unsigned int foobarbaz_len = tqstrlen( foobarbaz ); - -static const char * foobarbaz_dotstuffed = "..Foo bar baz"; -static const unsigned int foobarbaz_dotstuffed_len = tqstrlen( foobarbaz_dotstuffed ); - -static const char * foobarbaz_lf = ".Foo bar baz\n"; -static const unsigned int foobarbaz_lf_len = tqstrlen( foobarbaz_lf ); - -static const char * foobarbaz_crlf = "..Foo bar baz\r\n"; -static const unsigned int foobarbaz_crlf_len = tqstrlen( foobarbaz_crlf ); - -static void checkSuccessfulTransferCommand( bool, bool, bool, bool, bool ); - -int main( int, char** ) { - - // FIXME: Port this to new API. -#if 0 - SMTPProtocol smtp; - Response r; - TransactionState ts, ts2; - - // - // EHLO / HELO - // - - smtp.clear(); - EHLOCommand ehlo( &smtp, "mail.example.com" ); - // flags - assert( ehlo.closeConnectionOnError() ); - assert( ehlo.mustBeLastInPipeline() ); - assert( !ehlo.mustBeFirstInPipeline() ); - - // initial state - assert( !ehlo.isComplete() ); - assert( !ehlo.doNotExecute( 0 ) ); - assert( !ehlo.needsResponse() ); - - // dynamics 1: EHLO succeeds - assert( ehlo.nextCommandLine( 0 ) == "EHLO mail.example.com\r\n" ); - assert( !ehlo.isComplete() ); // EHLO may fail and we then try HELO - assert( ehlo.needsResponse() ); - r.clear(); - r.parseLine( "250-mail.example.net\r\n" ); - r.parseLine( "250-PIPELINING\r\n" ); - r.parseLine( "250 8BITMIME\r\n" ); - assert( ehlo.processResponse( r, 0 ) == true ); - assert( ehlo.isComplete() ); - assert( !ehlo.needsResponse() ); - assert( smtp.lastErrorCode == 0 ); - assert( smtp.lastErrorMessage.isNull() ); - - // dynamics 2: EHLO fails with "unknown command" - smtp.clear(); - EHLOCommand ehlo2( &smtp, "mail.example.com" ); - ehlo2.nextCommandLine( 0 ); - r.clear(); - r.parseLine( "500 unknown command\r\n" ); - assert( ehlo2.processResponse( r, 0 ) == true ); - assert( !ehlo2.isComplete() ); - assert( !ehlo2.needsResponse() ); - assert( ehlo2.nextCommandLine( 0 ) == "HELO mail.example.com\r\n" ); - assert( ehlo2.isComplete() ); - assert( ehlo2.needsResponse() ); - r.clear(); - r.parseLine( "250 mail.example.net\r\n" ); - assert( ehlo2.processResponse( r, 0 ) == true ); - assert( !ehlo2.needsResponse() ); - assert( smtp.lastErrorCode == 0 ); - assert( smtp.lastErrorMessage.isNull() ); - - // dynamics 3: EHLO fails with unknown response code - smtp.clear(); - EHLOCommand ehlo3( &smtp, "mail.example.com" ); - ehlo3.nextCommandLine( 0 ); - r.clear(); - r.parseLine( "545 you don't know me\r\n" ); - assert( ehlo3.processResponse( r, 0 ) == false ); - assert( ehlo3.isComplete() ); - assert( !ehlo3.needsResponse() ); - assert( smtp.lastErrorCode == TDEIO::ERR_UNKNOWN ); - - // dynamics 4: EHLO _and_ HELO fail with "command unknown" - smtp.clear(); - EHLOCommand ehlo4( &smtp, "mail.example.com" ); - ehlo4.nextCommandLine( 0 ); - r.clear(); - r.parseLine( "500 unknown command\r\n" ); - ehlo4.processResponse( r, 0 ); - ehlo4.nextCommandLine( 0 ); - r.clear(); - r.parseLine( "500 unknown command\r\n" ); - assert( ehlo4.processResponse( r, 0 ) == false ); - assert( ehlo4.isComplete() ); - assert( !ehlo4.needsResponse() ); - assert( smtp.lastErrorCode == TDEIO::ERR_INTERNAL_SERVER ); - - // - // STARTTLS - // - - smtp.clear(); - StartTLSCommand tls( &smtp ); - // flags - assert( tls.closeConnectionOnError() ); - assert( tls.mustBeLastInPipeline() ); - assert( !tls.mustBeFirstInPipeline() ); - - // initial state - assert( !tls.isComplete() ); - assert( !tls.doNotExecute( 0 ) ); - assert( !tls.needsResponse() ); - - // dynamics 1: ok from server, TLS negotiation successful - ts.clear(); - ts2 = ts; - assert( tls.nextCommandLine( &ts ) == "STARTTLS\r\n" ); - assert( ts == ts2 ); - assert( tls.isComplete() ); - assert( tls.needsResponse() ); - r.clear(); - r.parseLine( "220 Go ahead" ); - smtp.startTLSReturnCode = 1; - assert( tls.processResponse( r, &ts ) == true ); - assert( !tls.needsResponse() ); - assert( smtp.lastErrorCode == 0 ); - - // dynamics 2: NAK from server - smtp.clear(); - StartTLSCommand tls2( &smtp ); - ts.clear(); - tls2.nextCommandLine( &ts ); - r.clear(); - r.parseLine( "454 TLS temporarily disabled" ); - smtp.startTLSReturnCode = 1; - assert( tls2.processResponse( r, &ts ) == false ); - assert( !tls2.needsResponse() ); - assert( smtp.lastErrorCode == TDEIO::ERR_SERVICE_NOT_AVAILABLE ); - - // dynamics 3: ok from server, TLS negotiation unsuccessful - smtp.clear(); - StartTLSCommand tls3( &smtp ); - ts.clear(); - tls3.nextCommandLine( &ts ); - r.clear(); - r.parseLine( "220 Go ahead" ); - smtp.startTLSReturnCode = -1; - assert( tls.processResponse( r, &ts ) == false ); - assert( !tls.needsResponse() ); - - // - // AUTH - // - - smtp.clear(); - TQStrIList mechs; - mechs.append( "PLAIN" ); - smtp.metadata["sasl"] = "PLAIN"; - AuthCommand auth( &smtp, mechs, "user", "pass" ); - // flags - assert( auth.closeConnectionOnError() ); - assert( auth.mustBeLastInPipeline() ); - assert( !auth.mustBeFirstInPipeline() ); - - // initial state - assert( !auth.isComplete() ); - assert( !auth.doNotExecute( 0 ) ); - assert( !auth.needsResponse() ); - - // dynamics 1: TLS, so AUTH should include initial-response: - smtp.usesTLS = true; - ts.clear(); - ts2 = ts; - assert( auth.nextCommandLine( &ts ) == "AUTH PLAIN dXNlcgB1c2VyAHBhc3M=\r\n" ); - assert( auth.isComplete() ); - assert( auth.needsResponse() ); - assert( ts == ts2 ); - r.clear(); - r.parseLine( "250 OK" ); - - // dynamics 2: No TLS, so AUTH should not include initial-response: - smtp.clear(); - smtp.metadata["sasl"] = "PLAIN"; - smtp.usesTLS = false; - AuthCommand auth2( &smtp, mechs, "user", "pass" ); - ts.clear(); - assert( auth2.nextCommandLine( &ts ) == "AUTH PLAIN\r\n" ); - assert( !auth2.isComplete() ); - assert( auth2.needsResponse() ); - r.clear(); - r.parseLine( "334 Go on" ); - assert( auth2.processResponse( r, &ts ) == true ); - assert( auth2.nextCommandLine( &ts ) == "dXNlcgB1c2VyAHBhc3M=\r\n" ); - assert( auth2.isComplete() ); - assert( auth2.needsResponse() ); - - // dynamics 3: LOGIN - smtp.clear(); - smtp.metadata["sasl"] = "LOGIN"; - mechs.clear(); - mechs.append( "LOGIN" ); - AuthCommand auth3( &smtp, mechs, "user", "pass" ); - ts.clear(); - ts2 = ts; - assert( auth3.nextCommandLine( &ts ) == "AUTH LOGIN\r\n" ); - assert( !auth3.isComplete() ); - assert( auth3.needsResponse() ); - r.clear(); - r.parseLine( "334 VXNlcm5hbWU6" ); - assert( auth3.processResponse( r, &ts ) == true ); - assert( !auth3.needsResponse() ); - assert( auth3.nextCommandLine( &ts ) == "dXNlcg==\r\n" ); - assert( !auth3.isComplete() ); - assert( auth3.needsResponse() ); - r.clear(); - r.parseLine( "334 go on" ); - assert( auth3.processResponse( r, &ts ) == true ); - assert( !auth3.needsResponse() ); - assert( auth3.nextCommandLine( &ts ) == "cGFzcw==\r\n" ); - assert( auth3.isComplete() ); - assert( auth3.needsResponse() ); - r.clear(); - r.parseLine( "250 OK" ); - assert( auth3.processResponse( r, &ts ) == true ); - assert( !auth3.needsResponse() ); - assert( !smtp.lastErrorCode ); - assert( ts == ts2 ); - - // - // MAIL FROM: - // - - smtp.clear(); - MailFromCommand mail( &smtp, "joe@user.org" ); - // flags - assert( !mail.closeConnectionOnError() ); - assert( !mail.mustBeLastInPipeline() ); - assert( !mail.mustBeFirstInPipeline() ); - - // initial state - assert( !mail.isComplete() ); - assert( !mail.doNotExecute( 0 ) ); - assert( !mail.needsResponse() ); - - // dynamics: success, no size, no 8bit - ts.clear(); - ts2 = ts; - assert( mail.nextCommandLine( &ts ) == "MAIL FROM:<joe@user.org>\r\n" ); - assert( ts2 == ts ); - assert( mail.isComplete() ); - assert( mail.needsResponse() ); - r.clear(); - r.parseLine( "250 Ok" ); - assert( mail.processResponse( r, &ts ) == true ); - assert( !mail.needsResponse() ); - assert( ts == ts2 ); - assert( smtp.lastErrorCode == 0 ); - - // dynamics: success, size, 8bit, but no SIZE, 8BITMIME caps - smtp.clear(); - MailFromCommand mail2( &smtp, "joe@user.org", true, 500 ); - ts.clear(); - ts2 = ts; - assert( mail2.nextCommandLine( &ts ) == "MAIL FROM:<joe@user.org>\r\n" ); - assert( ts == ts2 ); - - // dynamics: success, size, 8bit, SIZE, 8BITMIME caps - smtp.clear(); - MailFromCommand mail3( &smtp, "joe@user.org", true, 500 ); - ts.clear(); - ts2 = ts; - smtp.caps << "SIZE" << "8BITMIME" ; - assert( mail3.nextCommandLine( &ts ) == "MAIL FROM:<joe@user.org> BODY=8BITMIME SIZE=500\r\n" ); - assert( ts == ts2 ); - - // dynamics: failure - smtp.clear(); - MailFromCommand mail4( &smtp, "joe@user.org" ); - ts.clear(); - mail4.nextCommandLine( &ts ); - r.clear(); - r.parseLine( "503 Bad sequence of commands" ); - assert( mail4.processResponse( r, &ts ) == false ); - assert( mail4.isComplete() ); - assert( !mail4.needsResponse() ); - assert( ts.failed() ); - assert( !ts.failedFatally() ); - assert( smtp.lastErrorCode == 0 ); - - // - // RCPT TO: - // - - smtp.clear(); - RcptToCommand rcpt( &smtp, "joe@user.org" ); - // flags - assert( !rcpt.closeConnectionOnError() ); - assert( !rcpt.mustBeLastInPipeline() ); - assert( !rcpt.mustBeFirstInPipeline() ); - - // initial state - assert( !rcpt.isComplete() ); - assert( !rcpt.doNotExecute( 0 ) ); - assert( !rcpt.needsResponse() ); - - // dynamics: success - ts.clear(); - ts2 = ts; - assert( rcpt.nextCommandLine( &ts ) == "RCPT TO:<joe@user.org>\r\n" ); - assert( ts == ts2 ); - assert( rcpt.isComplete() ); - assert( rcpt.needsResponse() ); - r.clear(); - r.parseLine( "250 Ok" ); - assert( rcpt.processResponse( r, &ts ) == true ); - assert( !rcpt.needsResponse() ); - assert( ts.atLeastOneRecipientWasAccepted() ); - assert( !ts.haveRejectedRecipients() ); - assert( !ts.failed() ); - assert( !ts.failedFatally() ); - assert( smtp.lastErrorCode == 0 ); - - // dynamics: failure - smtp.clear(); - RcptToCommand rcpt2( &smtp, "joe@user.org" ); - ts.clear(); - rcpt2.nextCommandLine( &ts ); - r.clear(); - r.parseLine( "530 5.7.1 Relaying not allowed!" ); - assert( rcpt2.processResponse( r, &ts ) == false ); - assert( rcpt2.isComplete() ); - assert( !rcpt2.needsResponse() ); - assert( !ts.atLeastOneRecipientWasAccepted() ); - assert( ts.haveRejectedRecipients() ); - assert( ts.rejectedRecipients().count() == 1 ); - assert( ts.rejectedRecipients().front().recipient == "joe@user.org" ); - assert( ts.failed() ); - assert( !ts.failedFatally() ); - assert( smtp.lastErrorCode == 0 ); - - // dynamics: success and failure combined - smtp.clear(); - RcptToCommand rcpt3( &smtp, "info@example.com" ); - RcptToCommand rcpt4( &smtp, "halloween@microsoft.com" ); - RcptToCommand rcpt5( &smtp, "joe@user.org" ); - ts.clear(); - rcpt3.nextCommandLine( &ts ); - r.clear(); - r.parseLine( "530 5.7.1 Relaying not allowed!" ); - rcpt3.processResponse( r, &ts ); - - rcpt4.nextCommandLine( &ts ); - r.clear(); - r.parseLine( "250 Ok" ); - rcpt4.processResponse( r, &ts ); - - rcpt5.nextCommandLine( &ts ); - r.clear(); - r.parseLine( "250 Ok" ); - assert( ts.failed() ); - assert( !ts.failedFatally() ); - assert( ts.haveRejectedRecipients() ); - assert( ts.atLeastOneRecipientWasAccepted() ); - assert( smtp.lastErrorCode == 0 ); - - // - // DATA (init) - // - - smtp.clear(); - DataCommand data( &smtp ); - // flags - assert( !data.closeConnectionOnError() ); - assert( data.mustBeLastInPipeline() ); - assert( !data.mustBeFirstInPipeline() ); - - // initial state - assert( !data.isComplete() ); - assert( !data.doNotExecute( 0 ) ); - assert( !data.needsResponse() ); - - // dynamics: success - ts.clear(); - assert( data.nextCommandLine( &ts ) == "DATA\r\n" ); - assert( data.isComplete() ); - assert( data.needsResponse() ); - assert( ts.dataCommandIssued() ); - assert( !ts.dataCommandSucceeded() ); - r.clear(); - r.parseLine( "354 Send data, end in <CR><LF>.<CR><LF>" ); - assert( data.processResponse( r, &ts ) == true ); - assert( !data.needsResponse() ); - assert( ts.dataCommandSucceeded() ); - assert( ts.dataResponse() == r ); - assert( smtp.lastErrorCode == 0 ); - - // dynamics: failure - smtp.clear(); - DataCommand data2( &smtp ); - ts.clear(); - data2.nextCommandLine( &ts ); - r.clear(); - r.parseLine( "551 No valid recipients" ); - assert( data2.processResponse( r, &ts ) == false ); - assert( !data2.needsResponse() ); - assert( !ts.dataCommandSucceeded() ); - assert( ts.dataResponse() == r ); - assert( smtp.lastErrorCode == 0 ); - - // - // DATA (transfer) - // - - TransferCommand xfer( &smtp, 0 ); - // flags - assert( !xfer.closeConnectionOnError() ); - assert( !xfer.mustBeLastInPipeline() ); - assert( xfer.mustBeFirstInPipeline() ); - - // initial state - assert( !xfer.isComplete() ); - assert( !xfer.needsResponse() ); - - // dynamics 1: DATA command failed - ts.clear(); - r.clear(); - r.parseLine( "551 no valid recipients" ); - ts.setDataCommandIssued( true ); - ts.setDataCommandSucceeded( false, r ); - assert( xfer.doNotExecute( &ts ) ); - - // dynamics 2: some recipients rejected, but not all - smtp.clear(); - TransferCommand xfer2( &smtp, 0 ); - ts.clear(); - ts.setRecipientAccepted(); - ts.addRejectedRecipient( "joe@user.org", "No relaying allowed" ); - ts.setDataCommandIssued( true ); - r.clear(); - r.parseLine( "354 go on" ); - ts.setDataCommandSucceeded( true, r ); - // ### will change with allow-partial-delivery option: - assert( xfer.doNotExecute( &ts ) ); - - // successful dynamics with all combinations of: - enum { - EndInLF = 1, - PerformDotStuff = 2, - UngetLast = 4, - Preloading = 8, - Error = 16, - EndOfOptions = 32 - }; - for ( unsigned int i = 0 ; i < EndOfOptions ; ++i ) - checkSuccessfulTransferCommand( i & Error, i & Preloading, i & UngetLast, - i & PerformDotStuff, i & EndInLF ); - - // - // NOOP - // - - smtp.clear(); - NoopCommand noop( &smtp ); - // flags - assert( !noop.closeConnectionOnError() ); - assert( noop.mustBeLastInPipeline() ); - assert( !noop.mustBeFirstInPipeline() ); - - // initial state - assert( !noop.isComplete() ); - assert( !noop.doNotExecute( &ts ) ); - assert( !noop.needsResponse() ); - - // dynamics: success (failure is tested with RSET) - assert( noop.nextCommandLine( 0 ) == "NOOP\r\n" ); - assert( noop.isComplete() ); - assert( noop.needsResponse() ); - r.clear(); - r.parseLine( "250 Ok" ); - assert( noop.processResponse( r, 0 ) == true ); - assert( noop.isComplete() ); - assert( !noop.needsResponse() ); - assert( smtp.lastErrorCode == 0 ); - assert( smtp.lastErrorMessage.isNull() ); - - // - // RSET - // - - smtp.clear(); - RsetCommand rset( &smtp ); - // flags - assert( rset.closeConnectionOnError() ); - assert( !rset.mustBeLastInPipeline() ); - assert( !rset.mustBeFirstInPipeline() ); - - // initial state - assert( !rset.isComplete() ); - assert( !rset.doNotExecute( &ts ) ); - assert( !rset.needsResponse() ); - - // dynamics: failure (success is tested with NOOP/QUIT) - assert( rset.nextCommandLine( 0 ) == "RSET\r\n" ); - assert( rset.isComplete() ); - assert( rset.needsResponse() ); - r.clear(); - r.parseLine( "502 command not implemented" ); - assert( rset.processResponse( r, 0 ) == false ); - assert( rset.isComplete() ); - assert( !rset.needsResponse() ); - assert( smtp.lastErrorCode == 0 ); // an RSET failure isn't worth it, is it? - assert( smtp.lastErrorMessage.isNull() ); - - // - // QUIT - // - - smtp.clear(); - QuitCommand quit( &smtp ); - // flags - assert( quit.closeConnectionOnError() ); - assert( quit.mustBeLastInPipeline() ); - assert( !quit.mustBeFirstInPipeline() ); - - // initial state - assert( !quit.isComplete() ); - assert( !quit.doNotExecute( 0 ) ); - assert( !quit.needsResponse() ); - - // dynamics 1: success - assert( quit.nextCommandLine( 0 ) == "QUIT\r\n" ); - assert( quit.isComplete() ); - assert( quit.needsResponse() ); - r.clear(); - r.parseLine( "221 Goodbye" ); - assert( quit.processResponse( r, 0 ) == true ); - assert( quit.isComplete() ); - assert( !quit.needsResponse() ); - assert( smtp.lastErrorCode == 0 ); - assert( smtp.lastErrorMessage.isNull() ); - - // dynamics 2: success - smtp.clear(); - QuitCommand quit2( &smtp ); - quit2.nextCommandLine( 0 ); - r.clear(); - r.parseLine( "500 unknown command" ); - assert( quit2.processResponse( r, 0 ) == false ); - assert( quit2.isComplete() ); - assert( !quit2.needsResponse() ); - assert( smtp.lastErrorCode == 0 ); // an QUIT failure isn't worth it, is it? - assert( smtp.lastErrorMessage.isNull() ); -#endif - - return 0; -} - -void checkSuccessfulTransferCommand( bool error, bool preload, bool ungetLast, - bool slaveDotStuff, bool mailEndsInNewline ) { - kdDebug() << " ===== checkTransferCommand( " - << error << ", " - << preload << ", " - << ungetLast << ", " - << slaveDotStuff << ", " - << mailEndsInNewline << " ) =====" << endl; - - SMTPProtocol smtp; - if ( slaveDotStuff ) - smtp.metadata["lf2crlf+dotstuff"] = "slave"; - - Response r; - - const char * s_pre = slaveDotStuff ? - mailEndsInNewline ? foobarbaz_lf : foobarbaz - : - mailEndsInNewline ? foobarbaz_crlf : foobarbaz_dotstuffed ; - const unsigned int s_pre_len = tqstrlen( s_pre ); - - const char * s_post = mailEndsInNewline ? foobarbaz_crlf : foobarbaz_dotstuffed ; - //const unsigned int s_post_len = tqstrlen( s_post ); - - TransferCommand xfer( &smtp, preload ? s_post : 0 ); - - TransactionState ts; - ts.setRecipientAccepted(); - ts.setDataCommandIssued( true ); - r.clear(); - r.parseLine( "354 ok" ); - ts.setDataCommandSucceeded( true, r ); - assert( !xfer.doNotExecute( &ts ) ); - if ( preload ) { - assert( xfer.nextCommandLine( &ts ) == s_post ); - assert( !xfer.isComplete() ); - assert( !xfer.needsResponse() ); - assert( !ts.failed() ); - assert( smtp.lastErrorCode == 0 ); - } - smtp.nextData.duplicate( s_pre, s_pre_len ); - smtp.nextDataReturnCode = s_pre_len; - assert( xfer.nextCommandLine( &ts ) == s_post ); - assert( !xfer.isComplete() ); - assert( !xfer.needsResponse() ); - assert( !ts.failed() ); - assert( smtp.lastErrorCode == 0 ); - smtp.nextData.resize( 0 ); - smtp.nextDataReturnCode = 0; - if ( ungetLast ) { - xfer.ungetCommandLine( xfer.nextCommandLine( &ts ), &ts ); - assert( !xfer.isComplete() ); - assert( !xfer.needsResponse() ); - assert( !ts.complete() ); - smtp.nextDataReturnCode = -1; // double read -> error - } - if ( mailEndsInNewline ) - assert( xfer.nextCommandLine( &ts ) == ".\r\n" ); - else - assert( xfer.nextCommandLine( &ts ) == "\r\n.\r\n" ); - assert( xfer.isComplete() ); - assert( xfer.needsResponse() ); - assert( !ts.complete() ); - assert( !ts.failed() ); - assert( smtp.lastErrorCode == 0 ); - r.clear(); - if ( error ) { - r.parseLine( "552 Exceeded storage allocation" ); - assert( xfer.processResponse( r, &ts ) == false ); - assert( !xfer.needsResponse() ); - assert( ts.complete() ); - assert( ts.failed() ); - assert( smtp.lastErrorCode == TDEIO::ERR_DISK_FULL ); - } else { - r.parseLine( "250 Message accepted" ); - assert( xfer.processResponse( r, &ts ) == true ); - assert( !xfer.needsResponse() ); - assert( ts.complete() ); - assert( !ts.failed() ); - assert( smtp.lastErrorCode == 0 ); - } -}; - -#define NDEBUG - -#include "command.cc" -#include "response.cc" -#include "transactionstate.cc" diff --git a/kioslave/smtp/test_headergeneration.cc b/kioslave/smtp/test_headergeneration.cc deleted file mode 100644 index 83d999c4a..000000000 --- a/kioslave/smtp/test_headergeneration.cc +++ /dev/null @@ -1,86 +0,0 @@ -#include "request.h" - -//#include <iostream> - -//using std::cout; -//using std::endl; - -int main( int , char ** ) { - static TQCString expected = - "From: mutz@kde.org\r\n" - "Subject: missing subject\r\n" - "To: joe@user.org,\r\n" - "\tvalentine@14th.february.org\r\n" - "Cc: boss@example.com\r\n" - "\n" - "From: Marc Mutz <mutz@kde.org>\r\n" - "Subject: missing subject\r\n" - "To: joe@user.org,\r\n" - "\tvalentine@14th.february.org\r\n" - "Cc: boss@example.com\r\n" - "\n" - "From: \"Mutz, Marc\" <mutz@kde.org>\r\n" - "Subject: missing subject\r\n" - "To: joe@user.org,\r\n" - "\tvalentine@14th.february.org\r\n" - "Cc: boss@example.com\r\n" - "\n" - "From: =?utf-8?b?TWFyYyBNw7Z0eg==?= <mutz@kde.org>\r\n" - "Subject: missing subject\r\n" - "To: joe@user.org,\r\n" - "\tvalentine@14th.february.org\r\n" - "Cc: boss@example.com\r\n" - "\n" - "From: mutz@kde.org\r\n" - "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n" - "To: joe@user.org,\r\n" - "\tvalentine@14th.february.org\r\n" - "Cc: boss@example.com\r\n" - "\n" - "From: Marc Mutz <mutz@kde.org>\r\n" - "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n" - "To: joe@user.org,\r\n" - "\tvalentine@14th.february.org\r\n" - "Cc: boss@example.com\r\n" - "\n" - "From: \"Mutz, Marc\" <mutz@kde.org>\r\n" - "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n" - "To: joe@user.org,\r\n" - "\tvalentine@14th.february.org\r\n" - "Cc: boss@example.com\r\n" - "\n" - "From: =?utf-8?b?TWFyYyBNw7Z0eg==?= <mutz@kde.org>\r\n" - "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n" - "To: joe@user.org,\r\n" - "\tvalentine@14th.february.org\r\n" - "Cc: boss@example.com\r\n" - "\n"; - - KioSMTP::Request request; - TQCString result; - - request.setEmitHeaders( true ); - request.setFromAddress( "mutz@kde.org" ); - request.addTo( "joe@user.org" ); - request.addTo( "valentine@14th.february.org" ); - request.addCc( "boss@example.com" ); - - result += request.headerFields() + '\n'; - result += request.headerFields( "Marc Mutz" ) + '\n'; - result += request.headerFields( "Mutz, Marc" ) + '\n'; - result += request.headerFields( "Marc Mötz" ) + '\n'; - - request.setSubject( "Blödes Subject" ); - - result += request.headerFields() + '\n'; - result += request.headerFields( "Marc Mutz" ) + '\n'; - result += request.headerFields( "Mutz, Marc" ) + '\n'; - result += request.headerFields( "Marc Mötz" ) + '\n'; - - //cout << "Result:\n" << result.data() << endl; - - return result == expected ? 0 : 1 ; -} - -#include "request.cc" - diff --git a/kioslave/smtp/test_responseparser.cc b/kioslave/smtp/test_responseparser.cc deleted file mode 100644 index e251aa291..000000000 --- a/kioslave/smtp/test_responseparser.cc +++ /dev/null @@ -1,107 +0,0 @@ -#include "response.h" -#include <assert.h> - -static const TQCString singleLineResponseCRLF = "250 OK\r\n"; -static const TQCString singleLineResponse = "250 OK"; - -static const TQCString multiLineResponse[] = { - "250-ktown.kde.org\r\n", - "250-STARTTLS\r\n", - "250-AUTH PLAIN DIGEST-MD5\r\n", - "250 PIPELINING\r\n" -}; -static const unsigned int numMultiLineLines = sizeof multiLineResponse / sizeof *multiLineResponse ; - -int main ( int, char** ) { - - KioSMTP::Response r; - assert( r.isValid() ); - assert( r.lines().empty() ); - assert( r.isWellFormed() ); - assert( r.code() == 0 ); - assert( r.isUnknown() ); - assert( !r.isComplete() ); - assert( !r.isOk() ); - r.parseLine( singleLineResponseCRLF.data(), - singleLineResponseCRLF.length() ); - assert( r.isWellFormed() ); - assert( r.isComplete() ); - assert( r.isValid() ); - assert( r.isPositive() ); - assert( r.isOk() ); - assert( r.code() == 250 ); - assert( r.errorCode() == 0 ); - assert( r.first() == 2 ); - assert( r.second() == 5 ); - assert( r.third() == 0 ); - assert( r.lines().count() == 1 ); - assert( r.lines().front() == "OK" ); - r.parseLine( singleLineResponse.data(), - singleLineResponse.length() ); - assert( !r.isValid() ); - r.clear(); - assert( r.isValid() ); - assert( r.lines().empty() ); - - r.parseLine( singleLineResponse.data(), - singleLineResponse.length() ); - assert( r.isWellFormed() ); - assert( r.isComplete() ); - assert( r.isValid() ); - assert( r.isPositive() ); - assert( r.isOk() ); - assert( r.code() == 250 ); - assert( r.first() == 2 ); - assert( r.second() == 5 ); - assert( r.third() == 0 ); - assert( r.lines().count() == 1 ); - assert( r.lines().front() == "OK" ); - r.parseLine( singleLineResponse.data(), - singleLineResponse.length() ); - assert( !r.isValid() ); - r.clear(); - assert( r.isValid() ); - - for ( unsigned int i = 0 ; i < numMultiLineLines ; ++i ) { - r.parseLine( multiLineResponse[i].data(), - multiLineResponse[i].length() ); - assert( r.isWellFormed() ); - if ( i < numMultiLineLines-1 ) - assert( !r.isComplete() ); - else - assert( r.isComplete() ); - assert( r.isValid() ); - assert( r.isPositive() ); - assert( r.code() == 250 ); - assert( r.first() == 2 ); - assert( r.second() == 5 ); - assert( r.third() == 0 ); - assert( r.lines().count() == i + 1 ); - } - assert( r.lines().back() == "PIPELINING" ); - - r.clear(); - r.parseLine( "230", 3 ); - assert( r.isValid() ); - assert( r.isWellFormed() ); // even though it isn't ;-) - assert( r.code() == 230 ); - assert( r.lines().count() == 1 ); - assert( r.lines().front().isNull() ); - - r.clear(); - r.parseLine( "230\r\n", 5 ); - assert( r.isValid() ); - assert( r.isWellFormed() ); // even though it isn't ;-) - assert( r.code() == 230 ); - assert( r.lines().count() == 1 ); - assert( r.lines().front().isNull() ); - - r.clear(); - r.parseLine( " 23 ok", 6 ); - assert( !r.isValid() ); - assert( !r.isWellFormed() ); - - return 0; -} - -#include "response.cc" diff --git a/kioslave/smtp/transactionstate.cc b/kioslave/smtp/transactionstate.cc deleted file mode 100644 index b34b45227..000000000 --- a/kioslave/smtp/transactionstate.cc +++ /dev/null @@ -1,114 +0,0 @@ -/* -*- c++ -*- - transactionstate.cc - - This file is part of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2003 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#include <config.h> - -#include "transactionstate.h" - -#include <kio/global.h> -#include <klocale.h> - -#include <tqstringlist.h> - -namespace KioSMTP { - - void TransactionState::setFailedFatally( int code, const TQString & msg ) { - mFailed = mFailedFatally = true; - mErrorCode = code; - mErrorMessage = msg; - } - - void TransactionState::setMailFromFailed( const TQString & addr, const Response & r ) { - setFailed(); - mErrorCode = TDEIO::ERR_NO_CONTENT; - if ( addr.isEmpty() ) - mErrorMessage = i18n("The server did not accept a blank sender address.\n" - "%1").arg( r.errorMessage() ); - else - mErrorMessage = i18n("The server did not accept the sender address \"%1\".\n" - "%2").arg( addr ).arg( r.errorMessage() ); - } - - void TransactionState::addRejectedRecipient( const RecipientRejection & r ) { - mRejectedRecipients.push_back( r ); - if ( mRcptToDenyIsFailure ) - setFailed(); - } - - void TransactionState::setDataCommandSucceeded( bool succeeded, const Response & r ) { - mDataCommandSucceeded = succeeded; - mDataResponse = r; - if ( !succeeded ) - setFailed(); - else if ( failed() ) - // can happen with pipelining: the server accepts the DATA, but - // we don't want to send the data, so force a connection - // shutdown: - setFailedFatally(); - } - - int TransactionState::errorCode() const { - if ( !failed() ) - return 0; - if ( mErrorCode ) - return mErrorCode; - if ( haveRejectedRecipients() || !dataCommandSucceeded() ) - return TDEIO::ERR_NO_CONTENT; - // ### what else? - return TDEIO::ERR_INTERNAL; - } - - TQString TransactionState::errorMessage() const { - if ( !failed() ) - return TQString::null; - - if ( !mErrorMessage.isEmpty() ) - return mErrorMessage; - - if ( haveRejectedRecipients() ) { - TQString msg = i18n("Message sending failed since the following recipients were rejected by the server:\n" - "%1"); - TQStringList recip; - for ( RejectedRecipientList::const_iterator it = mRejectedRecipients.begin() ; - it != mRejectedRecipients.end() ; ++it ) - recip.push_back( (*it).recipient + " (" + (*it).reason + ')' ); - return msg.arg( recip.join("\n") ); - } - - if ( !dataCommandSucceeded() ) - return i18n("The attempt to start sending the message content failed.\n" - "%1").arg( mDataResponse.errorMessage() ); - - // ### what else? - return i18n("Unhandled error condition. Please send a bug report."); - } - -} diff --git a/kioslave/smtp/transactionstate.h b/kioslave/smtp/transactionstate.h deleted file mode 100644 index d2f9ef797..000000000 --- a/kioslave/smtp/transactionstate.h +++ /dev/null @@ -1,185 +0,0 @@ -/* -*- c++ -*- - transactionstate.h - - This file is part of kio_smtp, the KDE SMTP kioslave. - Copyright (c) 2003 Marc Mutz <mutz@kde.org> - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#ifndef __KIOSMTP_TRANSACTIONSTATE_H__ -#define __KIOSMTP_TRANSACTIONSTATE_H__ - -#include "response.h" - -#include <tqstring.h> -#include <tqvaluelist.h> - -namespace KioSMTP { - - /** - @short A class modelling an SMTP transaction's state - - This class models SMTP transaction state, ie. the collective - result of the MAIL FROM:, RCPT TO: and DATA commands. This is - needed since e.g. a single failed RCPT TO: command does not - neccessarily fail the whole transaction (servers are free to - accept delivery for some recipients, but not for others). - - The class can operate in two modes, which differ in the way - failed recipients are handled. If @p rcptToDenyIsFailure is true - (the default), then any failing RCPT TO: will cause the - transaction to fail. Since at the point of RCPT TO: failure - detection, the DATA command may have already been sent - (pipelining), the only way to cancel the transaction is to take - down the connection hard (ie. without proper quit). - - Since that is not very nice behaviour, a second mode that is more - to the spirit of SMTP is provided that can cope with partially - failed RCPT TO: commands. - */ - class TransactionState { - public: - struct RecipientRejection { - RecipientRejection( const TQString & who=TQString::null, - const TQString & why=TQString::null ) - : recipient( who ), reason( why ) {} - TQString recipient; - TQString reason; -#ifdef KIOSMTP_COMPARATORS - bool operator==( const RecipientRejection & other ) const { - return recipient == other.recipient && reason == other.reason; - } -#endif - }; - typedef TQValueList<RecipientRejection> RejectedRecipientList; - - TransactionState( bool rcptToDenyIsFailure=true ) - : mErrorCode( 0 ), - mRcptToDenyIsFailure( rcptToDenyIsFailure ), - mAtLeastOneRecipientWasAccepted( false ), - mDataCommandIssued( false ), - mDataCommandSucceeded( false ), - mFailed( false ), - mFailedFatally( false ), - mComplete( false ) {} - - /** @return whether the transaction failed (e.g. the server - rejected all recipients. Graceful failure is handled after - transaction ends. */ - bool failed() const { return mFailed || mFailedFatally; } - void setFailed() { mFailed = true; } - - /** @return whether the failure was so grave that an immediate - untidy connection shutdown is in order (ie. @ref - smtp_close(false)). Fatal failure is handled immediately */ - bool failedFatally() const { return mFailedFatally; } - void setFailedFatally( int code=0, const TQString & msg=TQString::null ); - - /** @return whether the transaction was completed successfully */ - bool complete() const { return mComplete; } - void setComplete() { mComplete = true; } - - /** @return an appropriate KIO error code in case the transaction - failed, or 0 otherwise */ - int errorCode() const; - /** @return an appropriate error message in case the transaction - failed or TQString::null otherwise */ - TQString errorMessage() const; - - void setMailFromFailed( const TQString & addr, const Response & r ); - - bool dataCommandIssued() const { return mDataCommandIssued; } - void setDataCommandIssued( bool issued ) { mDataCommandIssued = issued; } - - bool dataCommandSucceeded() const { - return mDataCommandIssued && mDataCommandSucceeded; - } - void setDataCommandSucceeded( bool succeeded, const Response & r ); - - Response dataResponse() const { - return mDataResponse; - } - - bool atLeastOneRecipientWasAccepted() const { - return mAtLeastOneRecipientWasAccepted; - } - void setRecipientAccepted() { - mAtLeastOneRecipientWasAccepted = true; - } - - bool haveRejectedRecipients() const { - return !mRejectedRecipients.empty(); - } - RejectedRecipientList rejectedRecipients() const { - return mRejectedRecipients; - } - void addRejectedRecipient( const RecipientRejection & r ); - void addRejectedRecipient( const TQString & who, const TQString & why ) { - addRejectedRecipient( RecipientRejection( who, why ) ); - } - - void clear() { - mRejectedRecipients.clear(); - mDataResponse.clear(); - mAtLeastOneRecipientWasAccepted - = mDataCommandIssued - = mDataCommandSucceeded - = mFailed = mFailedFatally - = mComplete = false; - } - -#ifdef KIOSMTP_COMPARATORS - bool operator==( const TransactionState & other ) const { - return - mAtLeastOneRecipientWasAccepted == other.mAtLeastOneRecipientWasAccepted && - mDataCommandIssued == other.mDataCommandIssued && - mDataCommandSucceeded == other.mDataCommandSucceeded && - mFailed == other.mFailed && - mFailedFatally == other.mFailedFatally && - mComplete == other.mComplete && - mDataResponse.code() == other.mDataResponse.code() && - mRejectedRecipients == other.mRejectedRecipients; - } -#endif - - - private: - RejectedRecipientList mRejectedRecipients; - Response mDataResponse; - TQString mErrorMessage; - int mErrorCode; - bool mRcptToDenyIsFailure; - bool mAtLeastOneRecipientWasAccepted; - bool mDataCommandIssued; - bool mDataCommandSucceeded; - bool mFailed; - bool mFailedFatally; - bool mComplete; - }; - -} // namespace KioSMTP - -#endif // __KIOSMTP_TRANSACTIONSTATE_H__ |