23#include "servertest.h"
26#include <mailtransport/transportbase.h>
31#include <QProgressBar>
37using namespace MailTransport;
39namespace MailTransport {
41class ServerTestPrivate
54 QSet< int > connectionResults;
55 QHash< int, QList<int> > authenticationResults;
56 QSet< ServerTest::Capability > capabilityResults;
57 QHash< int, uint > customPorts;
58 QTimer *normalSocketTimer;
59 QTimer *secureSocketTimer;
60 QTimer *progressTimer;
62 QProgressBar *testProgress;
64 bool secureSocketFinished;
65 bool normalSocketFinished;
76 void handleSMTPIMAPResponse(
int type,
const QString &text );
79 const QString &response,
bool *shouldStartTLS );
80 QList< int > parseAuthenticationList(
const QStringList &authentications );
83 void slotNormalPossible();
84 void slotNormalNotPossible();
85 void slotSslPossible();
86 void slotSslNotPossible();
88 void slotReadNormal(
const QString &text );
89 void slotReadSecure(
const QString &text );
90 void slotUpdateProgress();
95ServerTestPrivate::ServerTestPrivate(
ServerTest *test )
96 : q( test ), testProgress( 0 ), secureSocketFinished( false ),
97 normalSocketFinished( false ), tlsFinished( false ),
98 normalPossible( true ), securePossible( true )
102void ServerTestPrivate::finalResult()
104 if ( !secureSocketFinished || !normalSocketFinished || !tlsFinished ) {
108 kDebug() <<
"Modes:" << connectionResults;
109 kDebug() <<
"Capabilities:" << capabilityResults;
110 kDebug() <<
"Normal:" << q->normalProtocols();
111 kDebug() <<
"SSL:" << q->secureProtocols();
112 kDebug() <<
"TLS:" << q->tlsProtocols();
114 if ( testProgress ) {
115 testProgress->hide();
117 progressTimer->stop();
118 secureSocketFinished =
false;
119 normalSocketFinished =
false;
120 tlsFinished = false ;
122 emit q->finished( connectionResults.toList() );
125QList< int > ServerTestPrivate::parseAuthenticationList(
const QStringList &authentications )
128 for ( QStringList::ConstIterator it = authentications.begin();
129 it != authentications.end(); ++it ) {
130 QString current = ( *it ).toUpper();
131 if ( current == QLatin1String(
"LOGIN" ) ) {
132 result << Transport::EnumAuthenticationType::LOGIN;
133 }
else if ( current == QLatin1String(
"PLAIN" ) ) {
134 result << Transport::EnumAuthenticationType::PLAIN;
135 }
else if ( current == QLatin1String(
"CRAM-MD5" ) ) {
136 result << Transport::EnumAuthenticationType::CRAM_MD5;
137 }
else if ( current == QLatin1String(
"DIGEST-MD5" ) ) {
138 result << Transport::EnumAuthenticationType::DIGEST_MD5;
139 }
else if ( current == QLatin1String(
"NTLM" ) ) {
140 result << Transport::EnumAuthenticationType::NTLM;
141 }
else if ( current == QLatin1String(
"GSSAPI" ) ) {
142 result << Transport::EnumAuthenticationType::GSSAPI;
143 }
else if ( current == QLatin1String(
"ANONYMOUS" ) ) {
144 result << Transport::EnumAuthenticationType::ANONYMOUS;
148 kDebug() << authentications << result;
153 if ( result.contains( Transport::EnumAuthenticationType::PLAIN ) ) {
154 result.removeAll( Transport::EnumAuthenticationType::LOGIN );
160void ServerTestPrivate::handleSMTPIMAPResponse(
int type,
const QString &text )
162 if ( !text.contains( QLatin1String(
"AUTH" ), Qt::CaseInsensitive ) ) {
163 kDebug() <<
"No authentication possible";
167 QStringList protocols;
168 protocols << QLatin1String(
"LOGIN" ) << QLatin1String(
"PLAIN" )
169 << QLatin1String(
"CRAM-MD5" ) << QLatin1String(
"DIGEST-MD5" )
170 << QLatin1String(
"NTLM" ) << QLatin1String(
"GSSAPI" )
171 << QLatin1String(
"ANONYMOUS" );
174 for (
int i = 0; i < protocols.count(); ++i ) {
175 if ( text.contains( protocols.at( i ), Qt::CaseInsensitive ) ) {
176 results.append( protocols.at( i ) );
180 authenticationResults[type] = parseAuthenticationList( results );
183 if ( authenticationResults[type].size() == 0 ) {
184 authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
187 kDebug() <<
"For type" << type <<
", we have:" << authenticationResults[type];
190void ServerTestPrivate::slotNormalPossible()
192 normalSocketTimer->stop();
193 connectionResults << Transport::EnumEncryption::None;
198 if ( testProtocol == IMAP_PROTOCOL ) {
199 socket->
write( QLatin1String(
"1 CAPABILITY" ) );
201 }
else if ( testProtocol == SMTP_PROTOCOL ) {
208 if ( !fakeHostname.isNull() ) {
209 hostname = fakeHostname;
211 hostname = QHostInfo::localHostName();
212 if ( hostname.isEmpty() ) {
213 hostname = QLatin1String(
"localhost.invalid" );
214 }
else if ( !hostname.contains( QChar::fromLatin1(
'.' ) ) ) {
215 hostname += QLatin1String(
".localnet" );
218 kDebug() <<
"Hostname for EHLO is" << hostname;
220 socket->
write( QLatin1String(
"EHLO " ) + hostname );
224void ServerTestPrivate::slotTlsDone()
229 slotReadNormal( QString() );
233 const QString &response,
bool *shouldStartTLS )
235 Q_ASSERT( shouldStartTLS != 0 );
241 QString responseWithoutCRLF = response;
242 responseWithoutCRLF.chop( 2 );
243 QRegExp re( QLatin1String(
"<[A-Za-z0-9\\.\\-_]+@[A-Za-z0-9\\.\\-_]+>$" ),
244 Qt::CaseInsensitive );
245 if ( responseWithoutCRLF.indexOf( re ) != -1 ) {
246 authenticationResults[type] << Transport::EnumAuthenticationType::APOP;
250 authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
254 if ( type == Transport::EnumEncryption::TLS &&
255 authenticationResults[Transport::EnumEncryption::None].
256 contains( Transport::EnumAuthenticationType::APOP ) ) {
257 authenticationResults[Transport::EnumEncryption::TLS]
258 << Transport::EnumAuthenticationType::APOP;
261 socket->
write( QLatin1String(
"CAPA" ) );
266 else if ( stage == 1 ) {
276 if ( response.contains( QLatin1String(
"TOP" ) ) ) {
279 if ( response.contains( QLatin1String(
"PIPELINING" ) ) ) {
282 if ( response.contains( QLatin1String(
"UIDL" ) ) ) {
285 if ( response.contains( QLatin1String(
"STLS" ) ) ) {
286 connectionResults << Transport::EnumEncryption::TLS;
287 popSupportsTLS =
true;
289 socket->
write( QLatin1String(
"AUTH" ) );
294 else if ( stage == 2 ) {
301 QString formattedReply = response;
304 formattedReply.chop( 3 );
307 formattedReply = formattedReply.right( formattedReply.size() -
308 formattedReply.indexOf( QLatin1Char(
'\n' ) ) - 1 );
310 formattedReply.replace( QLatin1Char(
' ' ), QLatin1Char(
'-' ) ).
311 replace( QLatin1String(
"\r\n" ), QLatin1String(
" " ) );
313 authenticationResults[type] +=
314 parseAuthenticationList( formattedReply.split( QLatin1Char(
' ' ) ) );
317 *shouldStartTLS = popSupportsTLS;
325void ServerTestPrivate::slotReadNormal(
const QString &text )
327 Q_ASSERT( encryptionMode != Transport::EnumEncryption::SSL );
328 static const int tlsHandshakeStage = 42;
330 kDebug() <<
"Stage" << normalStage + 1 <<
", Mode" << encryptionMode;
336 if ( normalStage == tlsHandshakeStage ) {
337 Q_ASSERT( encryptionMode == Transport::EnumEncryption::TLS );
339 normalSocket->startTLS();
343 bool shouldStartTLS =
false;
348 if ( testProtocol == POP_PROTOCOL ) {
349 if ( handlePopConversation( normalSocket, encryptionMode, normalStage, text,
350 &shouldStartTLS ) ) {
356 if ( normalStage == 0 ) {
357 sendInitialCapabilityQuery( normalSocket );
361 if ( text.contains( QLatin1String(
"STARTTLS" ), Qt::CaseInsensitive ) ) {
362 connectionResults << Transport::EnumEncryption::TLS;
363 shouldStartTLS =
true;
365 handleSMTPIMAPResponse( encryptionMode, text );
370 normalSocketFinished =
true;
374 if ( shouldStartTLS && encryptionMode == Transport::EnumEncryption::None ) {
375 kDebug() <<
"Trying TLS...";
376 connectionResults << Transport::EnumEncryption::TLS;
377 if ( testProtocol == POP_PROTOCOL ) {
378 normalSocket->write( QLatin1String(
"STLS" ) );
379 }
else if ( testProtocol == IMAP_PROTOCOL ) {
380 normalSocket->write( QLatin1String(
"2 STARTTLS" ) );
382 normalSocket->write( QLatin1String(
"STARTTLS" ) );
384 encryptionMode = Transport::EnumEncryption::TLS;
385 normalStage = tlsHandshakeStage;
395void ServerTestPrivate::slotReadSecure(
const QString &text )
398 if ( testProtocol == POP_PROTOCOL ) {
400 if ( handlePopConversation( secureSocket, Transport::EnumEncryption::SSL,
401 secureStage, text, &dummy ) ) {
405 if ( secureStage == 0 ) {
406 sendInitialCapabilityQuery( secureSocket );
409 handleSMTPIMAPResponse( Transport::EnumEncryption::SSL, text );
411 secureSocketFinished =
true;
415void ServerTestPrivate::slotNormalNotPossible()
417 normalSocketTimer->stop();
418 normalPossible =
false;
419 normalSocketFinished =
true;
424void ServerTestPrivate::slotSslPossible()
426 secureSocketTimer->stop();
427 connectionResults << Transport::EnumEncryption::SSL;
430void ServerTestPrivate::slotSslNotPossible()
432 secureSocketTimer->stop();
433 securePossible =
false;
434 secureSocketFinished =
true;
438void ServerTestPrivate::slotUpdateProgress()
440 if ( testProgress ) {
441 testProgress->setValue( testProgress->value() + 1 );
448 : QWidget( parent ), d( new ServerTestPrivate( this ) )
450 d->normalSocketTimer =
new QTimer(
this );
451 d->normalSocketTimer->setSingleShot(
true );
452 connect( d->normalSocketTimer, SIGNAL(timeout()), SLOT(slotNormalNotPossible()) );
454 d->secureSocketTimer =
new QTimer(
this );
455 d->secureSocketTimer->setSingleShot(
true );
456 connect( d->secureSocketTimer, SIGNAL(timeout()), SLOT(slotSslNotPossible()) );
458 d->progressTimer =
new QTimer(
this );
459 connect( d->progressTimer, SIGNAL(timeout()), SLOT(slotUpdateProgress()) );
471 d->connectionResults.clear();
472 d->authenticationResults.clear();
473 d->capabilityResults.clear();
474 d->popSupportsTLS =
false;
477 d->encryptionMode = Transport::EnumEncryption::None;
478 d->normalPossible =
true;
479 d->securePossible =
true;
481 if ( d->testProgress ) {
482 d->testProgress->setMaximum( 20 );
483 d->testProgress->setValue( 0 );
484 d->testProgress->setTextVisible(
true );
485 d->testProgress->show();
486 d->progressTimer->start( 1000 );
491 d->normalSocket->setObjectName( QLatin1String(
"normal" ) );
492 d->normalSocket->setServer( d->server );
493 d->normalSocket->setProtocol( d->testProtocol );
494 if ( d->testProtocol == IMAP_PROTOCOL ) {
495 d->normalSocket->setPort( IMAP_PORT );
496 d->secureSocket->setPort( IMAPS_PORT );
497 }
else if ( d->testProtocol == SMTP_PROTOCOL ) {
498 d->normalSocket->setPort( SMTP_PORT );
499 d->secureSocket->setPort( SMTPS_PORT );
500 }
else if ( d->testProtocol == POP_PROTOCOL ) {
501 d->normalSocket->setPort( POP_PORT );
502 d->secureSocket->setPort( POPS_PORT );
505 if ( d->customPorts.contains( Transport::EnumEncryption::None ) ) {
506 d->normalSocket->setPort( d->customPorts.value( Transport::EnumEncryption::None ) );
508 if ( d->customPorts.contains( Transport::EnumEncryption::SSL ) ) {
509 d->secureSocket->setPort( d->customPorts.value( Transport::EnumEncryption::SSL ) );
512 connect( d->normalSocket, SIGNAL(connected()), SLOT(slotNormalPossible()) );
513 connect( d->normalSocket, SIGNAL(failed()), SLOT(slotNormalNotPossible()) );
514 connect( d->normalSocket, SIGNAL(data(QString)),
515 SLOT(slotReadNormal(QString)) );
516 connect( d->normalSocket, SIGNAL(tlsDone()), SLOT(slotTlsDone()));
517 d->normalSocket->reconnect();
518 d->normalSocketTimer->start( 10000 );
520 d->secureSocket->setObjectName( QLatin1String(
"secure" ) );
521 d->secureSocket->setServer( d->server );
522 d->secureSocket->setProtocol( d->testProtocol + QLatin1Char(
's' ) );
523 d->secureSocket->setSecure(
true );
524 connect( d->secureSocket, SIGNAL(connected()), SLOT(slotSslPossible()) );
525 connect( d->secureSocket, SIGNAL(failed()), SLOT(slotSslNotPossible()) );
526 connect( d->secureSocket, SIGNAL(data(QString)),
527 SLOT(slotReadSecure(QString)) );
528 d->secureSocket->reconnect();
529 d->secureSocketTimer->start( 10000 );
539 return d->fakeHostname;
549 Q_ASSERT( encryptionMode == Transport::EnumEncryption::None ||
550 encryptionMode == Transport::EnumEncryption::SSL );
551 d->customPorts.insert( encryptionMode,
port );
556 d->testProgress = pb;
561 d->testProtocol = protocol;
564QString ServerTest::protocol()
566 return d->testProtocol;
569QString ServerTest::server()
576 Q_ASSERT( encryptionMode == Transport::EnumEncryption::None ||
577 encryptionMode == Transport::EnumEncryption::SSL );
578 if ( d->customPorts.contains( encryptionMode ) ) {
579 return d->customPorts.value(
static_cast<int>( encryptionMode ) );
585QProgressBar *ServerTest::progressBar()
587 return d->testProgress;
592 return d->authenticationResults[TransportBase::EnumEncryption::None];
597 return d->normalPossible;
602 return d->authenticationResults[TransportBase::EnumEncryption::TLS];
607 return d->authenticationResults[Transport::EnumEncryption::SSL];
612 return d->securePossible;
617 return d->capabilityResults.toList();
620#include "moc_servertest.cpp"
This class can be used to test certain server to see if they support stuff.
QList< int > secureProtocols()
Get the protocols for the SSL connections.
QList< int > normalProtocols()
Get the protocols for the normal connections.
void setProgressBar(QProgressBar *pb)
Makes pb the progressbar to use.
ServerTest(QWidget *parent=0)
Creates a new server test.
bool isNormalPossible()
tells you if the normal server is available
bool isSecurePossible()
tells you if the ssl server is available
void setProtocol(const QString &protocol)
Sets protocol the protocol to test, currently supported are "smtp", "pop" and "imap".
@ Pipelining
POP3 only. The server supports pipeplining of commands.
@ UIDL
POP3 only. The server has support for unique identifiers.
@ Top
POP3 only. The server supports fetching only the headers.
QList< Capability > capabilities() const
Get the special capabilities of the server.
int port(Transport::EnumEncryption::type encryptionMode)
void start()
Starts the test.
void setServer(const QString &server)
Sets the server to test.
QList< int > tlsProtocols()
Get the protocols for the TLS connections.
void setFakeHostname(const QString &fakeHostname)
Sets a fake hostname for the test.
~ServerTest()
Destroys the server test.
void setPort(Transport::EnumEncryption::type encryptionMode, uint port)
Set a custom port to use.
Responsible for communicating with the server, it's designed to work with the ServerTest class.
virtual void write(const QString &text)
Write text to the socket.
Internal file containing constant definitions etc.