summaryrefslogtreecommitdiffstats
path: root/tdeioslave/smtp/command.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tdeioslave/smtp/command.cc')
-rw-r--r--tdeioslave/smtp/command.cc606
1 files changed, 0 insertions, 606 deletions
diff --git a/tdeioslave/smtp/command.cc b/tdeioslave/smtp/command.cc
deleted file mode 100644
index 41bd8d58c..000000000
--- a/tdeioslave/smtp/command.cc
+++ /dev/null
@@ -1,606 +0,0 @@
-/* -*- c++ -*-
- command.cc
-
- This file is part of tdeio_smtp, the KDE SMTP tdeioslave.
- 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 <tdelocale.h>
-#include <kdebug.h>
-#include <kmdcodec.h>
-#include <tdeio/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 TDE 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 tdeio_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
-