23 #include "servertest.h"
26 #include <mailtransport/transportbase.h>
31 #include <QProgressBar>
35 #include <KLocalizedString>
38 using namespace MailTransport;
40 namespace MailTransport {
42 class ServerTestPrivate
55 QSet< int > connectionResults;
56 QHash< int, QList<int> > authenticationResults;
57 QSet< ServerTest::Capability > capabilityResults;
58 QHash< int, uint > customPorts;
59 QTimer *normalSocketTimer;
60 QTimer *secureSocketTimer;
61 QTimer *progressTimer;
63 QProgressBar *testProgress;
65 bool secureSocketFinished;
66 bool normalSocketFinished;
77 void handleSMTPIMAPResponse(
int type,
const QString &text );
80 const QString &response,
bool *shouldStartTLS );
81 QList< int > parseAuthenticationList(
const QStringList &authentications );
84 void slotNormalPossible();
85 void slotNormalNotPossible();
86 void slotSslPossible();
87 void slotSslNotPossible();
89 void slotReadNormal(
const QString &text );
90 void slotReadSecure(
const QString &text );
91 void slotUpdateProgress();
96 ServerTestPrivate::ServerTestPrivate(
ServerTest *test )
97 : q( test ), testProgress( 0 ), secureSocketFinished( false ),
98 normalSocketFinished( false ), tlsFinished( false ),
99 normalPossible( true ), securePossible( true )
103 void ServerTestPrivate::finalResult()
105 if ( !secureSocketFinished || !normalSocketFinished || !tlsFinished ) {
109 kDebug() <<
"Modes:" << connectionResults;
110 kDebug() <<
"Capabilities:" << capabilityResults;
111 kDebug() <<
"Normal:" << q->normalProtocols();
112 kDebug() <<
"SSL:" << q->secureProtocols();
113 kDebug() <<
"TLS:" << q->tlsProtocols();
115 if ( testProgress ) {
116 testProgress->hide();
118 progressTimer->stop();
119 secureSocketFinished =
false;
120 normalSocketFinished =
false;
121 tlsFinished = false ;
123 emit q->finished( connectionResults.toList() );
126 QList< int > ServerTestPrivate::parseAuthenticationList(
const QStringList &authentications )
129 for ( QStringList::ConstIterator it = authentications.begin();
130 it != authentications.end(); ++it ) {
131 QString current = ( *it ).toUpper();
132 if ( current == QLatin1String(
"LOGIN" ) ) {
133 result << Transport::EnumAuthenticationType::LOGIN;
134 }
else if ( current == QLatin1String(
"PLAIN" ) ) {
135 result << Transport::EnumAuthenticationType::PLAIN;
136 }
else if ( current == QLatin1String(
"CRAM-MD5" ) ) {
137 result << Transport::EnumAuthenticationType::CRAM_MD5;
138 }
else if ( current == QLatin1String(
"DIGEST-MD5" ) ) {
139 result << Transport::EnumAuthenticationType::DIGEST_MD5;
140 }
else if ( current == QLatin1String(
"NTLM" ) ) {
141 result << Transport::EnumAuthenticationType::NTLM;
142 }
else if ( current == QLatin1String(
"GSSAPI" ) ) {
143 result << Transport::EnumAuthenticationType::GSSAPI;
144 }
else if ( current == QLatin1String(
"ANONYMOUS" ) ) {
145 result << Transport::EnumAuthenticationType::ANONYMOUS;
149 kDebug() << authentications << result;
154 if ( result.contains( Transport::EnumAuthenticationType::PLAIN ) ) {
155 result.removeAll( Transport::EnumAuthenticationType::LOGIN );
161 void ServerTestPrivate::handleSMTPIMAPResponse(
int type,
const QString &text )
163 if ( !text.contains( QLatin1String(
"AUTH" ), Qt::CaseInsensitive ) ) {
164 kDebug() <<
"No authentication possible";
168 QStringList protocols;
169 protocols << QLatin1String(
"LOGIN" ) << QLatin1String(
"PLAIN" )
170 << QLatin1String(
"CRAM-MD5" ) << QLatin1String(
"DIGEST-MD5" )
171 << QLatin1String(
"NTLM" ) << QLatin1String(
"GSSAPI" )
172 << QLatin1String(
"ANONYMOUS" );
175 for (
int i = 0; i < protocols.count(); ++i ) {
176 if ( text.contains( protocols.at( i ), Qt::CaseInsensitive ) ) {
177 results.append( protocols.at( i ) );
181 authenticationResults[type] = parseAuthenticationList( results );
184 if ( authenticationResults[type].size() == 0 ) {
185 authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
188 kDebug() <<
"For type" << type <<
", we have:" << authenticationResults[type];
191 void ServerTestPrivate::slotNormalPossible()
193 normalSocketTimer->stop();
194 connectionResults << Transport::EnumEncryption::None;
199 if ( testProtocol == IMAP_PROTOCOL ) {
200 socket->
write( QLatin1String(
"1 CAPABILITY" ) );
202 }
else if ( testProtocol == SMTP_PROTOCOL ) {
209 if ( !fakeHostname.isNull() ) {
210 hostname = fakeHostname;
212 hostname = QHostInfo::localHostName();
213 if ( hostname.isEmpty() ) {
214 hostname = QLatin1String(
"localhost.invalid" );
215 }
else if ( !hostname.contains( QChar::fromLatin1(
'.' ) ) ) {
216 hostname += QLatin1String(
".localnet" );
219 kDebug() <<
"Hostname for EHLO is" << hostname;
221 socket->
write( QLatin1String(
"EHLO " ) + hostname );
225 void ServerTestPrivate::slotTlsDone()
230 slotReadNormal( QString() );
234 const QString &response,
bool *shouldStartTLS )
236 Q_ASSERT( shouldStartTLS != 0 );
242 QString responseWithoutCRLF = response;
243 responseWithoutCRLF.chop( 2 );
244 QRegExp re( QLatin1String(
"<[A-Za-z0-9\\.\\-_]+@[A-Za-z0-9\\.\\-_]+>$" ),
245 Qt::CaseInsensitive );
246 if ( responseWithoutCRLF.indexOf( re ) != -1 ) {
247 authenticationResults[type] << Transport::EnumAuthenticationType::APOP;
251 authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
255 if ( type == Transport::EnumEncryption::TLS &&
256 authenticationResults[Transport::EnumEncryption::None].
257 contains( Transport::EnumAuthenticationType::APOP ) ) {
258 authenticationResults[Transport::EnumEncryption::TLS]
259 << Transport::EnumAuthenticationType::APOP;
262 socket->
write( QLatin1String(
"CAPA" ) );
267 else if ( stage == 1 ) {
277 if ( response.contains( QLatin1String(
"TOP" ) ) ) {
280 if ( response.contains( QLatin1String(
"PIPELINING" ) ) ) {
283 if ( response.contains( QLatin1String(
"UIDL" ) ) ) {
286 if ( response.contains( QLatin1String(
"STLS" ) ) ) {
287 connectionResults << Transport::EnumEncryption::TLS;
288 popSupportsTLS =
true;
290 socket->
write( QLatin1String(
"AUTH" ) );
295 else if ( stage == 2 ) {
302 QString formattedReply = response;
305 formattedReply.chop( 3 );
308 formattedReply = formattedReply.right( formattedReply.size() -
309 formattedReply.indexOf( QLatin1Char(
'\n' ) ) - 1 );
311 formattedReply.replace( QLatin1Char(
' ' ), QLatin1Char(
'-' ) ).
312 replace( QLatin1String(
"\r\n" ), QLatin1String(
" " ) );
314 authenticationResults[type] +=
315 parseAuthenticationList( formattedReply.split( QLatin1Char(
' ' ) ) );
318 *shouldStartTLS = popSupportsTLS;
326 void ServerTestPrivate::slotReadNormal(
const QString &text )
328 Q_ASSERT( encryptionMode != Transport::EnumEncryption::SSL );
329 static const int tlsHandshakeStage = 42;
331 kDebug() <<
"Stage" << normalStage + 1 <<
", Mode" << encryptionMode;
337 if ( normalStage == tlsHandshakeStage ) {
338 Q_ASSERT( encryptionMode == Transport::EnumEncryption::TLS );
340 normalSocket->startTLS();
344 bool shouldStartTLS =
false;
349 if ( testProtocol == POP_PROTOCOL ) {
350 if ( handlePopConversation( normalSocket, encryptionMode, normalStage, text,
351 &shouldStartTLS ) ) {
357 if ( normalStage == 0 ) {
358 sendInitialCapabilityQuery( normalSocket );
362 if ( text.contains( QLatin1String(
"STARTTLS" ), Qt::CaseInsensitive ) ) {
363 connectionResults << Transport::EnumEncryption::TLS;
364 shouldStartTLS =
true;
366 handleSMTPIMAPResponse( encryptionMode, text );
371 normalSocketFinished =
true;
375 if ( shouldStartTLS && encryptionMode == Transport::EnumEncryption::None ) {
376 kDebug() <<
"Trying TLS...";
377 connectionResults << Transport::EnumEncryption::TLS;
378 if ( testProtocol == POP_PROTOCOL ) {
379 normalSocket->write( QLatin1String(
"STLS" ) );
380 }
else if ( testProtocol == IMAP_PROTOCOL ) {
381 normalSocket->write( QLatin1String(
"2 STARTTLS" ) );
383 normalSocket->write( QLatin1String(
"STARTTLS" ) );
385 encryptionMode = Transport::EnumEncryption::TLS;
386 normalStage = tlsHandshakeStage;
396 void ServerTestPrivate::slotReadSecure(
const QString &text )
399 if ( testProtocol == POP_PROTOCOL ) {
401 if ( handlePopConversation( secureSocket, Transport::EnumEncryption::SSL,
402 secureStage, text, &dummy ) ) {
406 if ( secureStage == 0 ) {
407 sendInitialCapabilityQuery( secureSocket );
410 handleSMTPIMAPResponse( Transport::EnumEncryption::SSL, text );
412 secureSocketFinished =
true;
416 void ServerTestPrivate::slotNormalNotPossible()
418 normalSocketTimer->stop();
419 normalPossible =
false;
420 normalSocketFinished =
true;
425 void ServerTestPrivate::slotSslPossible()
427 secureSocketTimer->stop();
428 connectionResults << Transport::EnumEncryption::SSL;
431 void ServerTestPrivate::slotSslNotPossible()
433 secureSocketTimer->stop();
434 securePossible =
false;
435 secureSocketFinished =
true;
439 void ServerTestPrivate::slotUpdateProgress()
441 if ( testProgress ) {
442 testProgress->setValue( testProgress->value() + 1 );
449 : QWidget( parent ), d( new ServerTestPrivate( this ) )
451 d->normalSocketTimer =
new QTimer(
this );
452 d->normalSocketTimer->setSingleShot(
true );
453 connect( d->normalSocketTimer, SIGNAL(timeout()), SLOT(slotNormalNotPossible()) );
455 d->secureSocketTimer =
new QTimer(
this );
456 d->secureSocketTimer->setSingleShot(
true );
457 connect( d->secureSocketTimer, SIGNAL(timeout()), SLOT(slotSslNotPossible()) );
459 d->progressTimer =
new QTimer(
this );
460 connect( d->progressTimer, SIGNAL(timeout()), SLOT(slotUpdateProgress()) );
472 d->connectionResults.clear();
473 d->authenticationResults.clear();
474 d->capabilityResults.clear();
475 d->popSupportsTLS =
false;
478 d->encryptionMode = Transport::EnumEncryption::None;
479 d->normalPossible =
true;
480 d->securePossible =
true;
482 if ( d->testProgress ) {
483 d->testProgress->setMaximum( 20 );
484 d->testProgress->setValue( 0 );
485 d->testProgress->setTextVisible(
true );
486 d->testProgress->show();
487 d->progressTimer->start( 1000 );
492 d->normalSocket->setObjectName( QLatin1String(
"normal" ) );
493 d->normalSocket->setServer( d->server );
494 d->normalSocket->setProtocol( d->testProtocol );
495 if ( d->testProtocol == IMAP_PROTOCOL ) {
496 d->normalSocket->setPort( IMAP_PORT );
497 d->secureSocket->setPort( IMAPS_PORT );
498 }
else if ( d->testProtocol == SMTP_PROTOCOL ) {
499 d->normalSocket->setPort( SMTP_PORT );
500 d->secureSocket->setPort( SMTPS_PORT );
501 }
else if ( d->testProtocol == POP_PROTOCOL ) {
502 d->normalSocket->setPort( POP_PORT );
503 d->secureSocket->setPort( POPS_PORT );
506 if ( d->customPorts.contains( Transport::EnumEncryption::None ) ) {
507 d->normalSocket->setPort( d->customPorts.value( Transport::EnumEncryption::None ) );
509 if ( d->customPorts.contains( Transport::EnumEncryption::SSL ) ) {
510 d->secureSocket->setPort( d->customPorts.value( Transport::EnumEncryption::SSL ) );
513 connect( d->normalSocket, SIGNAL(connected()), SLOT(slotNormalPossible()) );
514 connect( d->normalSocket, SIGNAL(failed()), SLOT(slotNormalNotPossible()) );
515 connect( d->normalSocket, SIGNAL(data(QString)),
516 SLOT(slotReadNormal(QString)) );
517 connect( d->normalSocket, SIGNAL(tlsDone()), SLOT(slotTlsDone()));
518 d->normalSocket->reconnect();
519 d->normalSocketTimer->start( 10000 );
521 d->secureSocket->setObjectName( QLatin1String(
"secure" ) );
522 d->secureSocket->setServer( d->server );
523 d->secureSocket->setProtocol( d->testProtocol + QLatin1Char(
's' ) );
524 d->secureSocket->setSecure(
true );
525 connect( d->secureSocket, SIGNAL(connected()), SLOT(slotSslPossible()) );
526 connect( d->secureSocket, SIGNAL(failed()), SLOT(slotSslNotPossible()) );
527 connect( d->secureSocket, SIGNAL(data(QString)),
528 SLOT(slotReadSecure(QString)) );
529 d->secureSocket->reconnect();
530 d->secureSocketTimer->start( 10000 );
540 return d->fakeHostname;
550 Q_ASSERT( encryptionMode == Transport::EnumEncryption::None ||
551 encryptionMode == Transport::EnumEncryption::SSL );
552 d->customPorts.insert( encryptionMode, port );
557 d->testProgress = pb;
567 return d->testProtocol;
577 Q_ASSERT( encryptionMode == Transport::EnumEncryption::None ||
578 encryptionMode == Transport::EnumEncryption::SSL );
579 if ( d->customPorts.contains( encryptionMode ) ) {
580 return d->customPorts.value( static_cast<int>( encryptionMode ) );
588 return d->testProgress;
593 return d->authenticationResults[TransportBase::EnumEncryption::None];
598 return d->normalPossible;
603 return d->authenticationResults[TransportBase::EnumEncryption::TLS];
608 return d->authenticationResults[Transport::EnumEncryption::SSL];
613 return d->securePossible;
618 return d->capabilityResults.toList();
621 #include "moc_servertest.cpp"
void setFakeHostname(const QString &fakeHostname)
Sets a fake hostname for the test.
void setServer(const QString &server)
Sets the server to test.
POP3 only. The server supports fetching only the headers.
virtual void write(const QString &text)
Write text to the socket.
This class can be used to test certain server to see if they support stuff.
bool isNormalPossible()
tells you if the normal server is available
void setProtocol(const QString &protocol)
Sets protocol the protocol to test, currently supported are "smtp", "pop" and "imap".
ServerTest(QWidget *parent=0)
Creates a new server test.
bool isSecurePossible()
tells you if the ssl server is available
void setPort(Transport::EnumEncryption::type encryptionMode, uint port)
Set a custom port to use.
int port(Transport::EnumEncryption::type encryptionMode)
QList< Capability > capabilities() const
Get the special capabilities of the server.
~ServerTest()
Destroys the server test.
Responsible for communicating with the server, it's designed to work with the ServerTest class...
Internal file containing constant definitions etc.
QString server()
Returns the server to test.
POP3 only. The server supports pipeplining of commands.
QProgressBar * progressBar()
Returns the used progress bar.
QString protocol()
Returns the protocol.
QList< int > normalProtocols()
Get the protocols for the normal connections.
void start()
Starts the test.
QList< int > tlsProtocols()
Get the protocols for the TLS connections.
void setProgressBar(QProgressBar *pb)
Makes pb the progressbar to use.
POP3 only. The server has support for unique identifiers.
QList< int > secureProtocols()
Get the protocols for the SSL connections.