[Qt-interest] QTcpSocket with QTextStream
Louis Hoefler
louis.hoefler at gmx.de
Fri Aug 20 08:50:44 CEST 2010
Hello everyone.
I use qt 4.6.3 with visual studio 2010.
I found a smtp class on the net, which is try to modify a little.
Sadly I get the error:
QSocketNotifier: socket notifiers cannot be enabled from another thread
and the conversation with the smtp server stops.
The error is shown after the function sendLine() is called from nextLine().
After that, nothing happens anymore.
Can someone tell me what I am doing wrong?
Thank you, Louis Hoefler
//------------------------------------------- smtp.cpp
/***************************************************************************
*
* http://sourceforge.net/projects/nlcreator/
*
* QNewsletterCreator - Business Email Client for Mass Mails
* Nuntius Leo - Personal Qt Email Client
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA. http://www.gnu.org/copyleft/library.html
*
* Please report all bugs and problems to the project admins:
* http://sourceforge.net/projects/nlcreator/
*
*
* Copyright by dontinelli at users.sourceforge.net if no additional copyright
information is given
* otherwise copyright by given authors/organizations
* and modfified, e.g. ported, by dontinelli at users.sourceforge.net.
* Some code has been taken from
* http://sourceforge.net/projects/lhmail - License : GNU Library General
Public License
* Authors: lukasz.iwaszkiewicz at gmail.com
* lukasz.iwaszkiewicz at lefthand.com.pl, lukasz.iwaszkiewicz at software.com.pl
* Copyright (C) 2004/2005 LeftHand sp.z.o.o. info at lefthand.com.pl
*
****************************************************************************
*/
#include "smtp.h"
Smtp::Smtp(const QString &lsmtpusername, const QString &lsmtppass, const
QString &lsmtphost, bool &smtpNeedLogin, bool &isWindowsServer, bool
&sendSmtpHelo, QObject *parent):
QThread(parent),error(false),newMail(false),
readyToSend(false),preserveMails(false),
state(Disconnected),read_state(Disconnected),sentMail(false),
quitAfterSending(false),mailsSent(0) {
smtpusername = lsmtpusername;
smtppass = lsmtppass;
smtphost = lsmtphost;
windowsServer = isWindowsServer;
if(windowsServer)
lineEnding = "\r\n";
else
lineEnding = "\r";
sendHelo = sendSmtpHelo;
needLogin = smtpNeedLogin;
tcpStream = 0;
smtpsocket = 0;
running = false;
qDebug() << "running" << running;
return;
}
void Smtp::exitLoop() {
qDebug() << "Smtp::exitLoop()";
mutex.lock();
running=false;
mutex.unlock();
}
void Smtp::run() {
qDebug() << "Smtp::run()";
running = true;
smtpsocket = new QTcpSocket();
tcpStream = new QTextStream(smtpsocket);
connect( smtpsocket, SIGNAL(disconnected()), this, SLOT(exitLoop()) );
readyToSend = false;
ErrorMSG.clear();
Timeout = 50 * 1000;
qDebug() << "Config server smtp connect to:" << smtphost;
qDebug() << "Host:" << smtphost << ", User:" << smtpusername << ",
Password:" << smtppass;
qDebug() << "windowsServer:" << windowsServer << ", needLogin:" << needLogin
<< ", SendHelo:" << sendHelo;
connect( this, SIGNAL(ConnectorSuccess()), this, SLOT(ReadLiner()) );
connect( this, SIGNAL(sendNextLine()), this, SLOT(nextLine()) );
smtpsocket->connectToHost(smtphost, 25);
if(smtpsocket->waitForConnected(Timeout)) {
qDebug() << "connected to:" << smtphost;
QCoreApplication::processEvents();
if(/*smtpsocket->waitForReadyRead(Timeout)*/ true) { //BUG: Some times this
function does not return, even if we are connected. Maybe becouse the server
does not send anything if the connection persisted?
qDebug() << "emit from waitForReadyRead connect go can read";
emit ConnectorSuccess();
emit status(tr("Connected to host"));
}
} else {
qDebug() << "error" << smtpsocket->errorString() << smtphost;
emit ErrorCloseAll();
}
connect( smtpsocket, SIGNAL(readyRead()), this, SLOT(grabLine()) );
while(running) {
QCoreApplication::processEvents();
//exec();
if(readyToSend && queuedMails.size()>0) {
mutex.lock();
Mail *m=queuedMails.takeFirst();
mutex.unlock();
sendMail(m,quitAfterSending);
}
//qDebug() << quitAfterSending << sentMail << queuedMails.size();
if(quitAfterSending && sentMail && queuedMails.size()<=0)
disconnectSmtp();
}
qDebug() << "end";
quit();
delete tcpStream;
tcpStream = 0;
delete smtpsocket;
smtpsocket = 0;
}
void Smtp::queueMail(Mail *m, bool qas) {
qDebug() << "Smtp::queueMail()";
if(readyToSend && queuedMails.size()==0) {
mutex.lock();
quitAfterSending=qas;
mutex.unlock();
sendMail(m,qas);
return;
}
mutex.lock();
quitAfterSending=qas;
queuedMails.append(m);
//qDebug()<<"appended queued mail";
mutex.unlock();
//if(!running) start();
//mutex.unlock();
}
void Smtp::sendMail(Mail *m, bool qas) {
qDebug() << "Smtp::sendMail()";
qDebug() << readyToSend << "qas:" << qas;
if(!readyToSend) {
qDebug() << "not ready: queue mail";
queueMail(m,qas);
return;
}
mutex.lock();
quitAfterSending = qas;
qDebug() << qas;
readyToSend = false;
newMail = true;
emit status(tr("Send mail"));
from = m->from();
if(from.contains("<")) {
from = from.mid(from.indexOf("<")+1);
from = from.left(from.indexOf(">"));
}
if(m->bcc() != "")
bcc=m->bcc().split(QRegExp(",|;"));
if(m->cc() != "")
bcc<<m->cc().split(QRegExp(",|;"));
//m->emptyBcc();
rcpt = m->to();
message = m->getSendData();
read_state = Rcpt;
mutex.unlock();
sendLine("MAIL FROM: " + from + lineEnding);
if(preserveMails)
currentMail = m;
else
delete m;
}
void Smtp::disconnectSmtp() {
//disconnect(this, SIGNAL(ConnectorSuccess()), this ,SLOT(ReadLiner()));
//disconnect(this, SIGNAL(sendNextLine()), this ,SLOT(PutsendNextLine()));
read_state = Close;
nextLine();
}
void Smtp::ReadLiner() {
qDebug() << "Smtp::ReadLiner()";
int loops = 0;
while(!tcpStream->atEnd()) {
loops++;
response = tcpStream->readLine();
qDebug() << loops << " in line" << response;
}
if(response.size() > 0) {
RemoteServerName = response;
mailstatus = response.left(3);
if(mailstatus == "220") {
qDebug() << "connected with status" << mailstatus;
response = "";
if(sendHelo) {
read_state = SendHelo;
}
else {
read_state = SendAuthType;
}
emit sendNextLine();
}
} else {
qDebug() << "Smtp::ReadLiner(): Connect error, connection closed";
emit ErrorCloseAll();
}
}
Smtp::~Smtp() {
delete smtpsocket;
delete tcpStream;
}
/* LINE SENDER */
void Smtp::nextLine() {
qDebug() << "Smtp::nextLine()";
State current = read_state;
switch(current) {
case SendHelo:
qDebug() << "case SendHelo";
if(needLogin)
read_state = SendAuthType;
else
read_state = AuthOk;
response = "";
if(windowsServer)
sendLine("EHLO" + lineEnding); //TODO: send the dns of the current
machine
else
sendLine("HELO" + lineEnding); //TODO: send the dns of the current
machine
break;
case SendAuthType:
qDebug() << "case SendAuthType";
if(response.size() > 0) {
ErrorMSG.append(response);
qDebug() << "1---- " << response;
read_state = SendAuthUser;
response = "";
sendLine("AUTH LOGIN" + lineEnding);
}
else {
qDebug() << "Connection lost (AUTH LOGIN)";
response = "";
emit ErrorCloseAll();
}
break;
case SendAuthUser:
qDebug() << "case SendAuthUser";
if(response.size() > 0) {
ErrorMSG.append(response);
qDebug() << "2---- " << response;
read_state = SendAuthPassword;
response = "";
sendLine(encodeBase64(smtpusername) + lineEnding); //send username
}
else {
qDebug() << "Connection lost (USERNAME)";
response = "";
emit ErrorCloseAll();
}
break;
case SendAuthPassword:
qDebug() << "case SendAuthPassword";
if (response.size() > 0) {
qDebug() << "3---- " << response;
ErrorMSG.append(response);
read_state = AuthOk;
response = "";
sendLine(encodeBase64(smtppass) + lineEnding); //send password
}
else {
qDebug() << "Connection lost (PASSWORD)";
response = "";
emit ErrorCloseAll();
}
break;
case AuthOk:
qDebug() << "case AuthOk";
if(response.size() > 0) {
qDebug() << "4---- " << response;
ErrorMSG.append(response);
if(response.contains("successful", Qt::CaseInsensitive)
|| response.contains("ok", Qt::CaseInsensitive)) {
response = "";
read_state = Noop;
emit status(tr("Login successful"));
emit sendNextLine();
}
else {
qDebug() << "Connection lost4.1";
emit ErrorCloseAll();
}
}
else {
qDebug() << "Connection lost4.2";
response = "";
emit ErrorCloseAll();
}
break;
case Rcpt:
//if (!newMail) break;
if(response.size() > 0) {
qDebug() << "5---- " << response;
read_state = Data;
qDebug() << "send RCPT";
sendLine("RCPT TO: " + rcpt + lineEnding);
}
else {
qDebug() << "Connection lost (Rcpt)";
emit ErrorCloseAll();
}
break;
case Data:
if (response.size() > 0) {
qDebug() << "6---- " << response;
if(bcc.size()>0){
read_state = Data;
qDebug() << "send BCC";
sendLine("RCPT TO: " + bcc.takeFirst() + lineEnding);
}
else {
ErrorMSG.append(response);
read_state = Send;
sendLine("DATA" + lineEnding);
}
} else {
qDebug() << "Connection lost (Data)";
emit ErrorCloseAll();
}
//response = "";
break;
case Send:
if(!response.contains("not", Qt::CaseInsensitive)) {
qDebug() << "7---- " << response;
ErrorMSG.append(response);
response = "";
read_state = Sent;
qDebug() << "send MESSAGE";
sendLine(message + lineEnding + "." + lineEnding);
}
else {
qDebug() << "Connection lost (Send)";
response = "";
emit ErrorCloseAll();
}
break;
case Sent:
if(response.left(3) == "354") {
qDebug() << "8---- " << response;
}
else {
if(response.size()
&& (response.contains("ok", Qt::CaseInsensitive)
|| response.contains("accepted", Qt::CaseInsensitive))) {
ErrorMSG.append(response);
read_state = Noop;
qDebug() << "Mail to " << rcpt << " successfully sent";
response = "";
if(preserveMails) emit mailSent(currentMail);
emit status(tr("Mail successfully sent"));
mutex.lock();
mailsSent++;
sentMail=true;
mutex.unlock();
sendLine("NOOP" + lineEnding);
} else {
qDebug() << "Connection lost (Sent)";
response = "";
emit ErrorCloseAll();
}
}
break;
case Noop:
if(response == "") {
qDebug() << "send NOOP";
sendLine("NOOP" + lineEnding);
}
else {
qDebug() << "9---- " << response;
QCoreApplication::processEvents();
qDebug() << "queuedMails.size" << queuedMails.size();
qDebug() << mailsSent << queuedMails.size() << quitAfterSending;
if(queuedMails.size()>0) {
mutex.lock();
readyToSend=true;
Mail *m=queuedMails.takeFirst();
mutex.unlock();
sendMail(m,quitAfterSending);
}
else {
mutex.lock();
readyToSend=true;
mutex.unlock();
emit ReadyToSend();
}
qDebug() << "Signal ReadyToSend emitted";
response = "";
}
break;
case Close:
read_state = Quit;
emit status(tr("Disconnect Smtp"));
sendLine("QUIT" + lineEnding);
break;
case Quit:
qDebug() << "10---- " << response;
ErrorMSG.append(response);
smtpsocket->disconnectFromHost();
qDebug() << "disconnectFromHost";
emit status(tr("Disconnected"));
emit SuccessQuit();
response = "";
if(quitAfterSending)
exitLoop();
break;
default:
qDebug() << "ERROR! last loop or false line emit...";
emit ErrorCloseAll();
break;
}
}
/* SENDER AND RECIVER
*/
void Smtp::sendLine(QString senddata) {
qDebug() << "Smtp::sendLine()";
*tcpStream << senddata.toAscii();
tcpStream->flush();
}
void Smtp::grabLine() {
qDebug() << "Smtp::grabLine()";
int loops = 0;
QString incommingData = "";
while(!tcpStream->atEnd()) {
QCoreApplication::processEvents();
loops++;
QString opera = tcpStream->readLine();
if(loops==1)
incommingData.append(opera);
else
incommingData.append("\n"+opera);
qDebug() << loops << "|#" << opera << "#|";
response = incommingData;
}
emit sendNextLine();
}
/*
void Smtp::disconnected() {
qDebug() <<"disconneted";
qDebug() << "error " << smtpsocket->errorString();
}
void Smtp::connected() {
output.append("connected");
qDebug() << "Connected ";
} */
QString Smtp::encodeBase64( QString xml ) {
qDebug() << "Smtp::encodeBase64()";
QByteArray text;
text.append(xml);
return text.toBase64();
}
QString Smtp::decodeBase64( QString xml ) {
qDebug() << "Smtp::decodeBase64()";
QByteArray xcode("");
xcode.append(xml);
QByteArray precode(QByteArray::fromBase64(xcode));
QString notetxt = precode.data();
return notetxt;
}
QString Smtp::TimeStampMail() {
qDebug() << "Smtp::TimeStampMail()";
/* Date: Mon, 08 May 2006 17:57:52 +0200 */
/* Date: Sun, 28 May 2006 06:32:25 -0420 */
QLocale english(QLocale::English,QLocale::UnitedKingdom);
QDateTime dt = QDateTime::currentDateTime();
QDate timecute = QDate::currentDate();
QString day_en = english.dayName(timecute.dayOfWeek(),QLocale::ShortFormat);
QString month_en = english.monthName(timecute.month(),QLocale::ShortFormat);
QString last = dt.toString("yyyy hh:mm:ss");
QString maildate = QString( "Date: %1, %2 %3 %4 +0200" ).arg( day_en ,
QString::number(timecute.day()), month_en , last );
qDebug() << maildate;
return maildate;
}
//---------------------------------------------------- smtp.h
/***************************************************************************
*
* http://sourceforge.net/projects/nlcreator/
*
* QNewsletterCreator - Business Email Client for Mass Mails
* Nuntius Leo - Personal Qt Email Client
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA. http://www.gnu.org/copyleft/library.html
*
* Please report all bugs and problems to the project admins:
* http://sourceforge.net/projects/nlcreator/
*
*
* Copyright by dontinelli at users.sourceforge.net if no additional copyright
information is given
* otherwise copyright by given authors/organizations
* and modfified, e.g. ported, by dontinelli at users.sourceforge.net.
* Some code has been taken from
* http://sourceforge.net/projects/lhmail - License : GNU Library General
Public License
* Authors: lukasz.iwaszkiewicz at gmail.com
* lukasz.iwaszkiewicz at lefthand.com.pl, lukasz.iwaszkiewicz at software.com.pl
* Copyright (C) 2004/2005 LeftHand sp.z.o.o. info at lefthand.com.pl
*
****************************************************************************
*/
#ifndef SMTP_H
#define SMTP_H
#include <QtNetwork>
#include <QApplication>
#include <QString>
#include <QTextStream>
#include <QDebug>
#include <QMessageBox>
#include <QDateTime>
#include <QDate>
#include <QThread>
#include "mail.h"
enum State {
Wait,
Disconnected,
SendHelo,
SendAuthType,
SendAuthUser,
SendAuthPassword,
AuthOk,
Rcpt,
Data,
Send,
Sent,
Noop,
Close,
Quit,
None
};
/**
* Usage: Build a Mail, build a smtp-object, start thread with start(), call
sendMail(Mail *m) when
* ReadyToSend() is emitted. For disconnecting, call disconnectSmtp();
* If smtp should be destroyed after the sending, connect the
terminate()-signal with the
* distroying routine. It is, however, also possible to send another mail
after having called run().
*
*/
#ifdef Q_OS_WIN32
#ifdef BUILD_DLL
#define DLL_MAKRO __declspec(dllexport)
#else
#define DLL_MAKRO __declspec(dllimport)
#endif
#else
#define DLL_MAKRO
#endif
class DLL_MAKRO Smtp : public QThread {
Q_OBJECT
public:
Smtp(const QString &lsmtpusername, const QString &lsmtppass, const QString
&lsmtphost, bool &smtpNeedLogin, bool &isWindowsServer, bool &sendSmtpHelo,
QObject *parent);
~Smtp();
QStringList ErrorMSG;
void setPreserveMails(bool p){preserveMails=p;};
// Send the mail
void queueMail(Mail *m, bool qas=false);
void sendMail(Mail *m, bool qas=false);
// Disconnect the socket
void disconnectSmtp();
bool error;
bool isRunning() { return running; };
int sentMails() { return mailsSent; };
int mailsToSend() { return queuedMails.size(); };
protected:
// start the thread and connect to the server
void run();
signals:
void status( const QString &);
void ConnectorSuccess();
void connected();
void sendNextLine();
void ErrorCloseAll();
void SuccessQuit();
void ReadyToSend();
void mailSent(Mail *m);
private slots:
void grabLine();
void exitLoop();
void ReadLiner();
void nextLine();
void sendLine(QString senddata);
private:
bool newMail;
bool readyToSend;
bool preserveMails;
Mail *currentMail;
QList<Mail *> queuedMails;
bool windowsServer;
bool sendHelo;
bool needLogin;
QString lineEnding;
QString smtpusername;
QString smtppass;
QString smtphost;
QString message;
QString output;
QString RemoteServerName;
QString mailstatus;
State state;
State read_state;
bool sentMail;
bool quitAfterSending;
int mailsSent;
//QByteArray block;
//QDataStream out;
QTextStream *tcpStream;
QTcpSocket *smtpsocket;
QString from;
QStringList bcc;
QString rcpt;
QString response;
int Timeout;
QString encodeBase64( QString xml );
QString decodeBase64( QString xml );
QString TimeStampMail();
bool running;
QMutex mutex;
};
#endif
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20100820/9bc9b624/attachment.html
More information about the Qt-interest-old
mailing list