📄 smtpclient.cpp
字号:
/******************************************************************************** Copyright (C) 2000-2006 TROLLTECH ASA. All rights reserved.**** This file is part of the Phone Edition of the Qtopia Toolkit.**** Licensees holding a valid license agreement from Trolltech or any of its** authorized distributors may use this file in accordance with** the License Agreement provided with the Licensed Software.**** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for** information about Trolltech's Commercial License Agreements.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.********** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "smtpclient.h"#include "emailhandler.h"#include <qtopia/qtopiaapplication.h>#ifdef SMTPAUTH#include "common.h"#endifSmtpClient::SmtpClient(){#ifndef SMTPAUTH createSocket();#else socket = 0; _secureSocket = 0; _plainSocket = 0;#endif socketAuthenticate = new QTcpSocket(this); socketAuthenticate->setObjectName("smtpClient-Authenticate"); streamLogin = new QTextStream(socketAuthenticate); connect(socketAuthenticate, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError))); connect(socketAuthenticate, SIGNAL(readyRead()), this, SLOT(authenticate())); sending = false; authenticating = false;}void SmtpClient::createSocket(){#ifdef SMTPAUTH if(account->smtpEncryption() == MailAccount::Encrypt_SSL) { //previous == none if(socket && (socket != _secureSocket)) { socket->deleteLater(); delete stream; socket = 0; } //previous == tls if(_plainSocket) { _plainSocket->deleteLater(); _plainSocket = 0; _secureSocket->deleteLater(); _secureSocket = 0; delete stream; } //previous == ssl if(_secureSocket) return; _secureSocket = new QtSslSocket(QtSslSocket::Client,this); _secureSocket->setObjectName("smtpClient-secure"); _secureSocket->setPathToCACertDir(QtMail::sslCertsPath()); connect(_secureSocket,SIGNAL(connectionVerificationDone(QtSslSocket::VerifyResult, bool, const QString &)),SLOT(certCheckDone(QtSslSocket::VerifyResult,bool,const QString&))); socket = _secureSocket; } else { //previous == ssl or tls if(socket && (socket == _secureSocket)) { _secureSocket->deleteLater(); delete stream; _secureSocket = 0; socket = 0; } //previous == tls if(_plainSocket) { _plainSocket->deleteLater(); _plainSocket = 0; } //previous == none if(socket) return; socket = new QTcpSocket(this); socket->setObjectName("smtpClient"); }#else socket = new QTcpSocket(this); socket->setObjectName("smtpClient"); #endif stream = new QTextStream(socket); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError))); connect(socket, SIGNAL(connected()), this, SLOT(connectionEstablished())); connect(socket, SIGNAL(readyRead()), this, SLOT(incomingData())); connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(sent(qint64)) );}SmtpClient::~SmtpClient(){ delete socket;#ifdef SMTPAUTH delete _plainSocket;#endif delete socketAuthenticate; delete stream;}void SmtpClient::setAccount(MailAccount *_account){ account = _account;}void SmtpClient::newConnection(){ if (sending) { qWarning("socket in use, connection refused"); return; } #ifdef SMTPAUTH createSocket();#endif if ( !account || account->smtpServer().isEmpty() ) { qWarning("Tried to send an email without a account and/or smtp server"); status = Done; emit mailSent(-1); return; } if ( account->smtpServer().isEmpty() ) { status = Done; emit mailSent(-1); return; } // authenticate with POP first #ifdef SMTPAUTH if ( !account->mailServer().isEmpty() && (account->smtpAuthentication() == MailAccount::Auth_NONE)) {#else if(!account->mailServer().isEmpty()) {#endif authenticating = true; status = Init; sending = true; emit updateStatus(tr("DNS lookup")); socketAuthenticate->connectToHost( account->mailServer(), account->mailPort() ); } else { doSend(); }}void SmtpClient::doSend(){ status = Init; sending = true; authenticating = false; emit updateStatus(tr("DNS lookup")); sentSize = 0;#ifdef SMTPAUTH if(_secureSocket) //connectToHost not virtual _secureSocket->connectToHost(account->smtpServer(),account->smtpPort()); else#endif socket->connectToHost(account->smtpServer(), account->smtpPort() );}#ifdef SMTPAUTHQString SmtpClient::_toBase64(const QString& in) const{ QByteArray temp(in.toAscii().data(),in.length()); return MailMessage::encodeBase64(temp);}void SmtpClient::_switchSecure(){ _secureSocket = new QtSslSocket(QtSslSocket::Client,this); _secureSocket->setObjectName("smtpClient-secure"); _secureSocket->setPathToCACertDir(QtMail::sslCertsPath()); _secureSocket->setSocket(socket); connect(_secureSocket,SIGNAL(connectionVerificationDone(QtSslSocket::VerifyResult, bool, const QString &)),SLOT(certCheckDone(QtSslSocket::VerifyResult,bool,const QString&))); _plainSocket = socket; socket = _secureSocket; stream = new QTextStream(socket); connect(socket, SIGNAL(error( QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError))); connect(socket, SIGNAL(connected()), this, SLOT(connectionEstablished())); connect(socket, SIGNAL(readyRead()), this, SLOT(incomingData())); connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(sent(qint64)) ); _secureSocket->sslConnect();}#endifvoid SmtpClient::addMail(QString from, QString subject, QStringList to, QString body){ RawEmail mail; mail.from = from; mail.subject = subject; mail.to = to; mail.body = body; mailList.append(mail);}void SmtpClient::connectionEstablished(){#ifdef QTOPIA_PHONE emit updateStatus(tr("Connected"));#else emit updateStatus(tr("Connection established"));#endif #ifdef SMTPAUTH //qDebug(QString::number(status)); if(status == TLS) { //qDebug("Sending EHLO"); *stream << "EHLO qtmail\r\n" << flush; if(account->smtpAuthentication() != MailAccount::Auth_NONE) status = Auth; else status = From; }#endif}#ifdef SMTPAUTHvoid SmtpClient::certCheckDone(QtSslSocket::VerifyResult result, bool hostNameMatched, const QString& description) { Q_UNUSED(hostNameMatched) if(result == QtSslSocket::VerifyOk) return; qWarning(("SSL cert check failed: " + description).toAscii()); errorHandling(ErrLoginFailed, "");}#endifvoid SmtpClient::errorHandling(int status, QString msg){ if ( !sending ) return; if (authenticating) { qWarning("login failed"); //login failed, try sending anyway socketAuthenticate->close(); if (status == ErrCancel) { mailList.clear(); sending = false; emit errorOccurred(status, msg); return; } else { doSend(); } } else { socket->close(); //brutal, but I can't see any other way to delete //the outgoing buffer#ifndef SMTPAUTH delete stream; delete socket; createSocket();#endif mailList.clear(); sending = false; emit errorOccurred(status, msg); qWarning("socket closed"); }}void SmtpClient::socketError(QAbstractSocket::SocketError status){ if (authenticating) { //scoket fail, pop may be down, but try sending anyway socketAuthenticate->close(); doSend(); return; } else { socket->close(); } QString msg = tr("Error occurred"); mailList.clear(); sending = false; emit updateStatus(msg); emit errorOccurred(static_cast<int>(status), msg);}void SmtpClient::sent(qint64 size){ if (status == From || status == Quit) { sentSize += size; emit transferredSize(sentSize); }}void SmtpClient::authenticate(){ QString response; response = socketAuthenticate->readLine(); if ( account->accountType() == MailAccount::IMAP ) { if (status == Init ) { status = Done; *streamLogin << "A01 LOGIN " + account->mailUserName() + " " + account->mailPassword() + "\r\n" << flush; return; } else if ( status == Done ) { QString rsp = response.mid(3, response.indexOf(" ") ).trimmed(); if ( rsp.toUpper() != "OK") { errorHandling(ErrLoginFailed, ""); return; } status = Quit; *streamLogin << "A02 LOGOUT\r\n" << flush; return; } else if ( status == Quit ) { socketAuthenticate->close(); doSend(); return; } } if (status == Init) { status = Pass; *streamLogin << "USER " << account->mailUserName() << "\r\n" <<flush; return; } else if (status == Pass) { if (response[0] != '+') { errorHandling(ErrLoginFailed, ""); return; } status = Done; *streamLogin << "PASS " << account->mailPassword() << "\r\n" << flush; return; } else if (status == Done) { if (response[0] != '+') { errorHandling(ErrLoginFailed, ""); return; } status = Quit; *streamLogin << "QUIT\r\n" << flush; return; } else if ( status == Quit ) { socketAuthenticate->close(); doSend(); }}void SmtpClient::incomingData(){ QString response; QString line; if(!socket->canReadLine()) return; do { line = socket->readLine(); response += line; } while(socket->canReadLine() && line.length() != 0); switch(status) { case Init: { if (response[0] == '2') { status = From; mailItr = mailList.begin(); #ifdef SMTPAUTH if(account->smtpAuthentication() != MailAccount::Auth_NONE || account->smtpEncryption() == MailAccount::Encrypt_TLS) { *stream << "EHLO qtmail\r\n" << flush; if(account->smtpEncryption() == MailAccount::Encrypt_TLS) status = StartTLS; else status = Auth; } else#endif *stream << "HELO qtmail\r\n" << flush; } else errorHandling(ErrUnknownResponse, response); break; }#ifdef SMTPAUTH case StartTLS: { if(line[0] == '2') { *stream << "STARTTLS\r\n" << flush; status = TLS; } else errorHandling(ErrUnknownResponse,response); break; } case TLS: { qDebug("switching to secure-- status = %d",status); if(line[0] == '2') { _switchSecure(); } else errorHandling(ErrUnknownResponse,response); break; } case Auth: { if(line[0] == '2') { if(account->smtpAuthentication() == MailAccount::Auth_LOGIN) { *stream << "AUTH LOGIN \r\n" << flush; status = AuthUser; } else if(account->smtpAuthentication() == MailAccount::Auth_PLAIN) { QString temp = account->smtpUsername() + '\0' + account->smtpUsername() + '\0' + account->smtpPassword(); temp = _toBase64(temp); *stream << "AUTH PLAIN " << temp << "\r\n" << flush; status = From; } } else errorHandling(ErrUnknownResponse, response); break; } case AuthUser: { if(line[0] == '3') { *stream << _toBase64(account->smtpUsername()) << "\r\n" << flush; status = AuthPass; } else errorHandling(ErrUnknownResponse, response); break; } case AuthPass: { if(line[0] == '3') { *stream << _toBase64(account->smtpPassword()) << "\r\n" << flush; status = From; } else errorHandling(ErrUnknownResponse, response); break; }#endif case From: { if (response[0] == '2') { *stream << "MAIL FROM: " << mailItr->from << "\r\n" << flush; status = Recv; } else errorHandling(ErrUnknownResponse, response); break; } case Recv: { if (response[0] == '2') { it = mailItr->to.begin(); if (it == mailItr->to.end()) errorHandling(ErrUnknownResponse, "no recipients"); *stream << "RCPT TO: <" << *it << ">\r\n" << flush; status = MRcv; } else errorHandling(ErrUnknownResponse, response); break; } case MRcv: { if (response[0] == '2') { it++; if ( it != mailItr->to.end() ) { *stream << "RCPT TO: <" << *it << ">\r\n" << flush; break; } else { status = Data; } } else { errorHandling(ErrUnknownResponse, response); break; } } case Data: { if (response[0] == '2') { *stream << "DATA\r\n" << flush; status = Body; emit updateStatus(tr( "Sending: %1").arg(mailItr->subject) ); } else errorHandling(ErrUnknownResponse, response); break; } case Body: { if (response[0] == '3' || response[0] == '2') { *stream << mailItr->body << "\r\n.\r\n" << flush; mailItr++; if (mailItr != mailList.end()) { status = From; } else { status = Quit; } } else errorHandling(ErrUnknownResponse, response); break; } case Quit: { if ( response[0] == '2' || response[0] == '3' ) { *stream << "QUIT\r\n" << flush; status = Done; int count = mailList.count(); emit updateStatus( tr("Sent %1 messages").arg(count) ); mailList.clear(); sending = false; socket->close(); emit mailSent(count); emit mailSent(-1); } else errorHandling(ErrUnknownResponse, response); break; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -