Logo Search packages:      
Sourcecode: mailody version File versions  Download package

smtp.cpp

/* This file is part of the KDE project
   Copyright (C) 2006-2007 KovoKs <info@kovoks.nl>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   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.
*/

#include <qstringlist.h>
#include <qsocket.h>
#include <qregexp.h>
#include <qtimer.h>

#include <kapplication.h>
#include <kconfig.h>
#include <kmdcodec.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kpassdlg.h>
#include <kwallet.h>
using KWallet::Wallet;

#include "../libkmime/kmime_headers.h"

#include "socketsafe.h"
#include "setup.h"
#include "global.h"
#include "smtp.h"

namespace Mailody {

00043 SMTP::SMTP( QWidget* parent,  const char* name)
    : QWidget( parent, name ),
    m_socket(0),
    m_currentCommand(None),
    m_tls(false),
    m_tlsPossible(false),
    m_authPossible(false)
{
}

00053 SMTP::~SMTP()
{
}

void SMTP::slotTLS()
{
    // Ok, we can get here twice. the first time after the EHLO. Then we
    // do the tls-stuff and after that we do a new EHLO. The second time
    // we should not do the tls-stuff again, bug the login-stuff.

    static bool tlsdone = false;

    kdDebug() << "TLS wanted: " << m_tls << " possible: "
            << m_tlsPossible << "already done:" << tlsdone << endl;

    if (!m_tls || tlsdone)
    {
        slotLogin();
        return;
    }

    if (m_tls && m_tlsPossible)
    {
        tlsdone = true;
        m_currentCommand = TLS;
        m_socket->write("STARTTLS");
    }

    if (m_tls && !m_tlsPossible)
    {
        emit error(i18n("The server does not support TLS"));
        return;
    }
}

void SMTP::slotLogin()
{
    kdDebug() << "Auth wanted: " << m_authNeeded << " possible: "
            << m_authPossible << endl;

    if (!m_authNeeded)
    {
        m_currentCommand = Pass;
        slotRead(QString::null); // trigger next
        return;
    }

    if (m_authNeeded && !m_authPossible)
    {
        emit error(i18n("The server does not support authentication"));
        return;
    }

    m_currentCommand = Login;

    if (m_pass.isEmpty())
        manualAuth();
    else
    {
        m_socket->write("AUTH LOGIN");
    }
}

void SMTP::manualAuth()
{
    int result = KPasswordDialog::getPassword(m_pass,
                i18n("Could not find a valid password, please enter it here"));
    if (!m_pass)
    {
        emit error(i18n("No password to send"));
        return;
    }
    if (result == KPasswordDialog::Accepted)
        m_socket->write("AUTH LOGIN");
}

void SMTP::slotRead(const QString& dataIn)
{
    // kdDebug() << "Received: " << dataIn.stripWhiteSpace()
    //        << " for " << m_currentCommand << endl;

    static QString lastEmail;

    if (!m_socket)
        return;

    if (m_currentCommand == Connecting)
    {
        m_currentCommand = Helo;
        m_socket->write("EHLO localhost");
    }
    else if (m_currentCommand == Helo)
    {
        if (dataIn.find("STARTTLS") != -1)
            m_tlsPossible = true;

        if (dataIn.find("AUTH") != -1 &&
            dataIn.find("AUTH") < dataIn.find("LOGIN"))
            m_authPossible = true;

        if (dataIn.find("\n250 "))
            slotTLS();
    }
    else if (m_currentCommand == TLS)
    {
        if (dataIn.stripWhiteSpace().isEmpty())
        {
            m_currentCommand = Helo;
            m_socket->write("EHLO localhost");
        }
        else
        {
            emit error(i18n("TLS did not succeed"));
            return;
        }
    }
    else if (m_currentCommand == Login)
    {
        if (!dataIn.startsWith("334"))
        {
            emit error(i18n("Authentication did not succeed"));
            return;
        }
        m_currentCommand = User;
        m_socket->write(KCodecs::base64Encode(m_login));
    }
    else if (m_currentCommand == User)
    {
        if (!dataIn.startsWith("334"))
        {
            emit error(i18n("Authentication did not succeed"));
            return;
        }
        m_currentCommand = Pass;
        m_socket->write(KCodecs::base64Encode(m_pass));
    }
    else if (m_currentCommand == Pass)
    {
        if (!dataIn.startsWith("235") && m_authNeeded)
        {
            emit error(i18n("Authentication did not succeed"));
            return;
        }

        // Please remember, this can be the response to hte Helo or to
        // a previous Pass command.... TLS already send the headers, so
        // that should pass through....
        if (dataIn.find("250 ") > -1 || m_tls || !m_authNeeded)
        {
            m_currentCommand = From;
            m_socket->write("MAIL FROM:" + m_email);
        }
    }
    else if (m_currentCommand == From || !m_tos.isEmpty())
    {
        if (dataIn.stripWhiteSpace().isEmpty())
            return; // eat empty strings which can happen after tls

        if (dataIn.find("250") == -1)
        {
            if (dataIn.startsWith("501"))
                emit error(i18n("One of the emailaddress was refused by the "
                        "server. The refused address is: " + lastEmail));
            else
                emit error( dataIn );
            return;
        }

        m_currentCommand = Rcpt;
        QString to = m_tos.first();
        m_tos.pop_front();

        //only send the actual emailaddress, not the name.
        KMime::Headers::AddressField Address;
        Address.fromUnicodeString( to,"UTF-8");
        lastEmail = Address.email();

        m_socket->write("RCPT TO:" + lastEmail);
    }
    else if (m_currentCommand == Rcpt )
    {
        if (!dataIn.startsWith("250"))
        {
            if (dataIn.startsWith("501"))
                emit error(i18n("One of the emailaddress was refused by the "
                    "server. The refused address is: " + lastEmail));
            else
                emit error( dataIn );
            return;
        }
        m_currentCommand = Data;
        m_socket->write("DATA");
    }
    else if (m_currentCommand == Data)
    {
        if (!dataIn.startsWith("250") && !dataIn.startsWith("354"))
        {
            emit error( dataIn );
            return;
        }
        m_currentCommand = DataBody;
        m_socket->write(m_message);
        m_socket->write(".");
    }
    else if (m_currentCommand == DataBody)
    {
        if (!dataIn.startsWith("250") && !dataIn.startsWith("354"))
        {
            emit error( dataIn );
            return;
        }
        m_currentCommand = Done;
        m_socket->aboutToClose();     // prevent disconnect message.
        m_socket->write("QUIT");
    }
    else if (m_currentCommand == Done)
    {
        emit done();
    }
}

void SMTP::slotError(const QString& msg)
{
    kdDebug() << "error received from socket" << endl;
    emit error(msg);
}


00281 void SMTP::send(const QString identity, const QStringList& tos,
                const QString& body)
{
    m_tos = tos;
    m_message = body;

    if (m_socket)
    {
        m_socket->deleteLater();
        m_socket = 0;
    }

    KConfig* config = kapp->config();
    config->setGroup("identity_" + identity);
    QString smtp_server = config->readEntry("smtpServer");
    int safe = kapp->config()->readNumEntry("safeSMTP",0);
    m_name = config->readEntry("fullName");
    m_email = config->readEntry("emailAddress");
    m_authNeeded = kapp->config()->readBoolEntry("smtpNeedAuth", false);

    if (m_authNeeded)
    {
        m_login = kapp->config()->readEntry("smtpUserName");
        QString pass;
        Wallet* wallet = Wallet::openWallet(Wallet::NetworkWallet(),
                                            this->winId());
        if (wallet && wallet->isOpen() && wallet->hasFolder("mailody"))
        {
            wallet->setFolder( "mailody" );
            wallet->readPassword("smtpidentity_"+identity, pass);
            m_pass = pass;
        }
        delete wallet;
    }


    QString server = smtp_server.section(":",0,0);
    int port = smtp_server.section(":",1,1).toInt();
    switch(safe)
    {
        case 0:
            if (port == 0)
                port = 25;
            m_socket = new SocketSafe(this,"SMTP", server, port, SocketSafe::NONE);
            break;
        case 1:
            if (port == 0)
                port = 465;
            m_socket = new SocketSafe(this,"SMTP", server, port, SocketSafe::SSL);
            break;
        case 2:
            if (port == 0)
                port = 25;
            m_tls = true;
            m_socket = new SocketSafe(this,"SMTP", server, port, SocketSafe::TLS);
            break;
    }

    connect(m_socket, SIGNAL(data(const QString&)),
            SLOT(slotRead(const QString&)));
    connect(m_socket, SIGNAL(error(const QString&)),
            SLOT(slotError(const QString&)));

    m_currentCommand = Connecting;
    m_socket->reconnect();
}

}

#include "smtp.moc"

Generated by  Doxygen 1.6.0   Back to index