23 #include "servertest.h"
26 #include <mailtransport/transportbase.h>
31 #include <QProgressBar>
35 #include <KLocalizedString>
38 using namespace MailTransport;
40 namespace MailTransport
43 class ServerTestPrivate
56 QSet< int > connectionResults;
57 QHash< int, QList<int> > authenticationResults;
58 QSet< ServerTest::Capability > capabilityResults;
59 QHash< int, uint > customPorts;
60 QTimer *normalSocketTimer;
61 QTimer *secureSocketTimer;
62 QTimer *progressTimer;
64 QProgressBar *testProgress;
66 bool secureSocketFinished;
67 bool normalSocketFinished;
78 void handleSMTPIMAPResponse(
int type,
const QString &text );
81 const QString &response,
bool *shouldStartTLS );
82 QList< int > parseAuthenticationList(
const QStringList &authentications );
85 void slotNormalPossible();
86 void slotNormalNotPossible();
87 void slotSslPossible();
88 void slotSslNotPossible();
90 void slotReadNormal(
const QString &text );
91 void slotReadSecure(
const QString &text );
92 void slotUpdateProgress();
97 ServerTestPrivate::ServerTestPrivate(
ServerTest *test )
98 : q( test ), testProgress( 0 ), secureSocketFinished( false ),
99 normalSocketFinished( false ), tlsFinished( false ),
100 normalPossible( true ), securePossible( true )
104 void ServerTestPrivate::finalResult()
106 if ( !secureSocketFinished || !normalSocketFinished || !tlsFinished ) {
110 kDebug() <<
"Modes:" << connectionResults;
111 kDebug() <<
"Capabilities:" << capabilityResults;
112 kDebug() <<
"Normal:" << q->normalProtocols();
113 kDebug() <<
"SSL:" << q->secureProtocols();
114 kDebug() <<
"TLS:" << q->tlsProtocols();
116 if ( testProgress ) {
117 testProgress->hide();
119 progressTimer->stop();
120 secureSocketFinished =
false;
121 normalSocketFinished =
false;
122 tlsFinished = false ;
124 emit q->finished( connectionResults.toList() );
127 QList< int > ServerTestPrivate::parseAuthenticationList(
const QStringList &authentications )
130 for ( QStringList::ConstIterator it = authentications.begin();
131 it != authentications.end(); ++it ) {
132 QString current = (*it).toUpper();
133 if ( current == QLatin1String(
"LOGIN" ) ) {
134 result << Transport::EnumAuthenticationType::LOGIN;
135 }
else if ( current == QLatin1String(
"PLAIN" ) ) {
136 result << Transport::EnumAuthenticationType::PLAIN;
137 }
else if ( current == QLatin1String(
"CRAM-MD5" ) ) {
138 result << Transport::EnumAuthenticationType::CRAM_MD5;
139 }
else if ( current == QLatin1String(
"DIGEST-MD5" ) ) {
140 result << Transport::EnumAuthenticationType::DIGEST_MD5;
141 }
else if ( current == QLatin1String(
"NTLM" ) ) {
142 result << Transport::EnumAuthenticationType::NTLM;
143 }
else if ( current == QLatin1String(
"GSSAPI" ) ) {
144 result << Transport::EnumAuthenticationType::GSSAPI;
145 }
else if ( current == QLatin1String(
"ANONYMOUS" ) ) {
146 result << Transport::EnumAuthenticationType::ANONYMOUS;
150 kDebug() << authentications << result;
155 if ( result.contains( Transport::EnumAuthenticationType::PLAIN ) ) {
156 result.removeAll( Transport::EnumAuthenticationType::LOGIN );
162 void ServerTestPrivate::handleSMTPIMAPResponse(
int type,
const QString &text )
164 if ( !text.contains( QLatin1String(
"AUTH" ), Qt::CaseInsensitive ) ) {
165 kDebug() <<
"No authentication possible";
169 QStringList protocols;
170 protocols << QLatin1String(
"LOGIN" ) << QLatin1String(
"PLAIN" )
171 << QLatin1String(
"CRAM-MD5" ) << QLatin1String(
"DIGEST-MD5" )
172 << QLatin1String(
"NTLM" ) << QLatin1String(
"GSSAPI" )
173 << QLatin1String(
"ANONYMOUS" );
176 for (
int i = 0; i < protocols.count(); ++i ) {
177 if ( text.contains( protocols.at( i ), Qt::CaseInsensitive ) ) {
178 results.append( protocols.at( i ) );
182 authenticationResults[type] = parseAuthenticationList( results );
185 if ( authenticationResults[type].size() == 0 ) {
186 authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
189 kDebug() <<
"For type" << type <<
", we have:" << authenticationResults[type];
192 void ServerTestPrivate::slotNormalPossible()
194 normalSocketTimer->stop();
195 connectionResults << Transport::EnumEncryption::None;
200 if ( testProtocol == IMAP_PROTOCOL ) {
201 socket->
write( QLatin1String(
"1 CAPABILITY" ) );
204 else if ( testProtocol == SMTP_PROTOCOL ) {
211 if ( !fakeHostname.isNull() ) {
212 hostname = fakeHostname;
214 hostname = QHostInfo::localHostName();
215 if ( hostname.isEmpty() ) {
216 hostname = QLatin1String(
"localhost.invalid" );
217 }
else if ( !hostname.contains( QChar::fromAscii(
'.' ) ) ) {
218 hostname += QLatin1String(
".localnet" );
221 kDebug() <<
"Hostname for EHLO is" << hostname;
223 socket->
write( QLatin1String(
"EHLO " ) + hostname );
227 void ServerTestPrivate::slotTlsDone()
232 slotReadNormal( QString() );
236 const QString &response,
bool *shouldStartTLS )
238 Q_ASSERT( shouldStartTLS != 0 );
244 QString responseWithoutCRLF = response;
245 responseWithoutCRLF.chop( 2 );
246 QRegExp re( QLatin1String(
"<[A-Za-z0-9\\.\\-_]+@[A-Za-z0-9\\.\\-_]+>$" ),
247 Qt::CaseInsensitive );
248 if ( responseWithoutCRLF.indexOf( re ) != -1 ) {
249 authenticationResults[type] << Transport::EnumAuthenticationType::APOP;
253 authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
257 if ( type == Transport::EnumEncryption::TLS &&
258 authenticationResults[Transport::EnumEncryption::None].
259 contains( Transport::EnumAuthenticationType::APOP ) ) {
260 authenticationResults[Transport::EnumEncryption::TLS]
261 << Transport::EnumAuthenticationType::APOP;
264 socket->
write( QLatin1String(
"CAPA" ) );
269 else if ( stage == 1 ) {
279 if ( response.contains( QLatin1String(
"TOP" ) ) ) {
282 if ( response.contains( QLatin1String(
"PIPELINING" ) ) ) {
285 if ( response.contains( QLatin1String(
"UIDL" ) ) ) {
288 if ( response.contains( QLatin1String(
"STLS" ) ) ) {
289 connectionResults << Transport::EnumEncryption::TLS;
290 popSupportsTLS =
true;
292 socket->
write( QLatin1String(
"AUTH" ) );
297 else if ( stage == 2 ) {
304 QString formattedReply = response;
307 formattedReply.chop( 3 );
310 formattedReply = formattedReply.right( formattedReply.size() -
311 formattedReply.indexOf( QLatin1Char(
'\n' ) ) - 1 );
313 formattedReply.replace( QLatin1Char(
' ' ), QLatin1Char(
'-' ) ).
314 replace( QLatin1String(
"\r\n" ), QLatin1String(
" " ) );
316 authenticationResults[type] +=
317 parseAuthenticationList( formattedReply.split( QLatin1Char(
' ' ) ) );
320 *shouldStartTLS = popSupportsTLS;
328 void ServerTestPrivate::slotReadNormal(
const QString &text )
330 Q_ASSERT( encryptionMode != Transport::EnumEncryption::SSL );
331 static const int tlsHandshakeStage = 42;
333 kDebug() <<
"Stage" << normalStage + 1 <<
", Mode" << encryptionMode;
339 if ( normalStage == tlsHandshakeStage ) {
340 Q_ASSERT( encryptionMode == Transport::EnumEncryption::TLS );
342 normalSocket->startTLS();
346 bool shouldStartTLS =
false;
351 if ( testProtocol == POP_PROTOCOL ) {
352 if ( handlePopConversation( normalSocket, encryptionMode, normalStage, text,
353 &shouldStartTLS ) ) {
359 if ( normalStage == 0 ) {
360 sendInitialCapabilityQuery( normalSocket );
364 if ( text.contains( QLatin1String(
"STARTTLS" ), Qt::CaseInsensitive ) ) {
365 connectionResults << Transport::EnumEncryption::TLS;
366 shouldStartTLS =
true;
368 handleSMTPIMAPResponse( encryptionMode, text );
373 normalSocketFinished =
true;
377 if ( shouldStartTLS && encryptionMode == Transport::EnumEncryption::None ) {
378 kDebug() <<
"Trying TLS...";
379 connectionResults << Transport::EnumEncryption::TLS;
380 if ( testProtocol == POP_PROTOCOL ) {
381 normalSocket->write( QLatin1String(
"STLS" ) );
382 }
else if ( testProtocol == IMAP_PROTOCOL ) {
383 normalSocket->write( QLatin1String(
"2 STARTTLS" ) );
385 normalSocket->write( QLatin1String(
"STARTTLS" ) );
387 encryptionMode = Transport::EnumEncryption::TLS;
388 normalStage = tlsHandshakeStage;
398 void ServerTestPrivate::slotReadSecure(
const QString &text )
401 if ( testProtocol == POP_PROTOCOL ) {
403 if ( handlePopConversation( secureSocket, Transport::EnumEncryption::SSL,
404 secureStage, text, &dummy ) ) {
408 if ( secureStage == 0 ) {
409 sendInitialCapabilityQuery( secureSocket );
412 handleSMTPIMAPResponse( Transport::EnumEncryption::SSL, text );
414 secureSocketFinished =
true;
418 void ServerTestPrivate::slotNormalNotPossible()
420 normalSocketTimer->stop();
421 normalPossible =
false;
422 normalSocketFinished =
true;
427 void ServerTestPrivate::slotSslPossible()
429 secureSocketTimer->stop();
430 connectionResults << Transport::EnumEncryption::SSL;
433 void ServerTestPrivate::slotSslNotPossible()
435 secureSocketTimer->stop();
436 securePossible =
false;
437 secureSocketFinished =
true;
441 void ServerTestPrivate::slotUpdateProgress()
443 if ( testProgress ) {
444 testProgress->setValue( testProgress->value() + 1 );
451 : QWidget( parent ), d( new ServerTestPrivate( this ) )
453 d->normalSocketTimer =
new QTimer(
this );
454 d->normalSocketTimer->setSingleShot(
true );
455 connect( d->normalSocketTimer, SIGNAL(timeout()), SLOT(slotNormalNotPossible()) );
457 d->secureSocketTimer =
new QTimer(
this );
458 d->secureSocketTimer->setSingleShot(
true );
459 connect( d->secureSocketTimer, SIGNAL(timeout()), SLOT(slotSslNotPossible()) );
461 d->progressTimer =
new QTimer(
this );
462 connect( d->progressTimer, SIGNAL(timeout()), SLOT(slotUpdateProgress()) );
474 d->connectionResults.clear();
475 d->authenticationResults.clear();
476 d->capabilityResults.clear();
477 d->popSupportsTLS =
false;
480 d->encryptionMode = Transport::EnumEncryption::None;
481 d->normalPossible =
true;
482 d->securePossible =
true;
484 if ( d->testProgress ) {
485 d->testProgress->setMaximum( 20 );
486 d->testProgress->setValue( 0 );
487 d->testProgress->setTextVisible(
true );
488 d->testProgress->show();
489 d->progressTimer->start( 1000 );
494 d->normalSocket->setObjectName( QLatin1String(
"normal" ) );
495 d->normalSocket->setServer( d->server );
496 d->normalSocket->setProtocol( d->testProtocol );
497 if ( d->testProtocol == IMAP_PROTOCOL ) {
498 d->normalSocket->setPort( IMAP_PORT );
499 d->secureSocket->setPort( IMAPS_PORT );
500 }
else if ( d->testProtocol == SMTP_PROTOCOL ) {
501 d->normalSocket->setPort( SMTP_PORT );
502 d->secureSocket->setPort( SMTPS_PORT );
503 }
else if ( d->testProtocol == POP_PROTOCOL ) {
504 d->normalSocket->setPort( POP_PORT );
505 d->secureSocket->setPort( POPS_PORT );
508 if ( d->customPorts.contains( Transport::EnumEncryption::None ) ) {
509 d->normalSocket->setPort( d->customPorts.value( Transport::EnumEncryption::None ) );
511 if ( d->customPorts.contains( Transport::EnumEncryption::SSL ) ) {
512 d->secureSocket->setPort( d->customPorts.value( Transport::EnumEncryption::SSL ) );
515 connect( d->normalSocket, SIGNAL(connected()), SLOT(slotNormalPossible()) );
516 connect( d->normalSocket, SIGNAL(failed()), SLOT(slotNormalNotPossible()) );
517 connect( d->normalSocket, SIGNAL(data(QString)),
518 SLOT(slotReadNormal(QString)) );
519 connect( d->normalSocket, SIGNAL(tlsDone()), SLOT(slotTlsDone()));
520 d->normalSocket->reconnect();
521 d->normalSocketTimer->start( 10000 );
523 d->secureSocket->setObjectName( QLatin1String(
"secure" ) );
524 d->secureSocket->setServer( d->server );
525 d->secureSocket->setProtocol( d->testProtocol + QLatin1Char(
's' ) );
526 d->secureSocket->setSecure(
true );
527 connect( d->secureSocket, SIGNAL(connected()), SLOT(slotSslPossible()) );
528 connect( d->secureSocket, SIGNAL(failed()), SLOT(slotSslNotPossible()) );
529 connect( d->secureSocket, SIGNAL(data(QString)),
530 SLOT(slotReadSecure(QString)) );
531 d->secureSocket->reconnect();
532 d->secureSocketTimer->start( 10000 );
542 return d->fakeHostname;
552 Q_ASSERT( encryptionMode == Transport::EnumEncryption::None ||
553 encryptionMode == Transport::EnumEncryption::SSL );
554 d->customPorts.insert( encryptionMode, port );
559 d->testProgress = pb;
569 return d->testProtocol;
579 Q_ASSERT( encryptionMode == Transport::EnumEncryption::None ||
580 encryptionMode == Transport::EnumEncryption::SSL );
581 if ( d->customPorts.contains( encryptionMode ) ) {
582 return d->customPorts.value( static_cast<int>( encryptionMode ) );
590 return d->testProgress;
595 return d->authenticationResults[TransportBase::EnumEncryption::None];
600 return d->normalPossible;
605 return d->authenticationResults[TransportBase::EnumEncryption::TLS];
610 return d->authenticationResults[Transport::EnumEncryption::SSL];
615 return d->securePossible;
620 return d->capabilityResults.toList();
623 #include "servertest.moc"